Skip to content

Commit e096ce7

Browse files
authored
Implement property.__name__ attribute (RustPython#6230)
* Implement property.__name__ attribute Add getter and setter for the __name__ attribute on property objects. The getter returns the explicitly set name if available, otherwise falls back to the getter function's __name__. Raises AttributeError if no name is available, matching CPython 3.13 behavior. The implementation handles edge cases: - Returns None when explicitly set to None - Propagates non-AttributeError exceptions from getter's __getattr__ - Raises property-specific AttributeError when getter lacks __name__ This fix enables test_property_name in test_property.py to pass. * Refactor to use get_property_name in __name__ implementation Consolidate duplicate logic by making name_getter() use the existing get_property_name() helper method. This eliminates code duplication and improves maintainability. Changes: - Update get_property_name() to return PyResult<Option<PyObjectRef>> to properly handle and propagate non-AttributeError exceptions - Simplify name_getter() to delegate to get_property_name() - Update format_property_error() to handle the new return type This addresses review feedback about the relationship between get_property_name() and __name__ implementation. * style comment
1 parent 9e7d291 commit e096ce7

File tree

2 files changed

+35
-11
lines changed

2 files changed

+35
-11
lines changed

Lib/test/test_property.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ def test_gh_115618(self):
201201
self.assertIsNone(prop.fdel)
202202
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
203203

204-
@unittest.expectedFailure # TODO: RUSTPYTHON
205204
def test_property_name(self):
206205
def getter(self):
207206
return 42

vm/src/builtins/property.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,30 @@ impl GetDescriptor for PyProperty {
6767
#[pyclass(with(Constructor, Initializer, GetDescriptor), flags(BASETYPE))]
6868
impl PyProperty {
6969
// Helper method to get property name
70-
fn get_property_name(&self, vm: &VirtualMachine) -> Option<PyObjectRef> {
70+
// Returns the name if available, None if not found, or propagates errors
71+
fn get_property_name(&self, vm: &VirtualMachine) -> PyResult<Option<PyObjectRef>> {
7172
// First check if name was set via __set_name__
7273
if let Some(name) = self.name.read().as_ref() {
73-
return Some(name.clone());
74+
return Ok(Some(name.clone()));
7475
}
7576

76-
// Otherwise try to get __name__ from getter
77-
if let Some(getter) = self.getter.read().as_ref()
78-
&& let Ok(name) = getter.get_attr("__name__", vm)
79-
{
80-
return Some(name);
81-
}
77+
let getter = self.getter.read();
78+
let Some(getter) = getter.as_ref() else {
79+
return Ok(None);
80+
};
8281

83-
None
82+
match getter.get_attr("__name__", vm) {
83+
Ok(name) => Ok(Some(name)),
84+
Err(e) => {
85+
// If it's an AttributeError from the getter, return None
86+
// Otherwise, propagate the original exception (e.g., RuntimeError)
87+
if e.class().is(vm.ctx.exceptions.attribute_error) {
88+
Ok(None)
89+
} else {
90+
Err(e)
91+
}
92+
}
93+
}
8494
}
8595

8696
// Descriptor methods
@@ -143,6 +153,21 @@ impl PyProperty {
143153
self.deleter.read().clone()
144154
}
145155

156+
#[pygetset(name = "__name__")]
157+
fn name_getter(&self, vm: &VirtualMachine) -> PyResult {
158+
match self.get_property_name(vm)? {
159+
Some(name) => Ok(name),
160+
None => Err(
161+
vm.new_attribute_error("'property' object has no attribute '__name__'".to_owned())
162+
),
163+
}
164+
}
165+
166+
#[pygetset(name = "__name__", setter)]
167+
fn name_setter(&self, value: PyObjectRef) {
168+
*self.name.write() = Some(value);
169+
}
170+
146171
fn doc_getter(&self) -> Option<PyObjectRef> {
147172
self.doc.read().clone()
148173
}
@@ -288,7 +313,7 @@ impl PyProperty {
288313
error_type: &str,
289314
vm: &VirtualMachine,
290315
) -> PyResult<String> {
291-
let prop_name = self.get_property_name(vm);
316+
let prop_name = self.get_property_name(vm)?;
292317
let obj_type = obj.class();
293318
let qualname = obj_type.__qualname__(vm);
294319

0 commit comments

Comments
 (0)