Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
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.
  • Loading branch information
ever0de committed Oct 31, 2025
commit 0878b8e8460d081477b119fa357d2d42f95248b5
1 change: 0 additions & 1 deletion Lib/test/test_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,6 @@ def test_gh_115618(self):
self.assertIsNone(prop.fdel)
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_property_name(self):
def getter(self):
return 42
Expand Down
35 changes: 35 additions & 0 deletions vm/src/builtins/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,41 @@ impl PyProperty {
self.deleter.read().clone()
}

#[pygetset(name = "__name__")]
fn name_getter(&self, vm: &VirtualMachine) -> PyResult {
// If name was explicitly set via __set_name__ or direct assignment
// (even to None), return it as-is
if let Some(name) = self.name.read().as_ref() {
return Ok(name.clone());
}

// Fallback to getter's __name__ if available
if let Some(getter) = self.getter.read().as_ref() {
match getter.get_attr("__name__", vm) {
Ok(name) => Ok(name),
Err(e) => {
// If it's an AttributeError from the getter, convert to property's AttributeError
// Otherwise, propagate the original exception (e.g., RuntimeError)
if e.class().is(vm.ctx.exceptions.attribute_error) {
return Err(vm.new_attribute_error(
"'property' object has no attribute '__name__'".to_owned(),
));
}

Err(e)
}
}
} else {
// If no getter, raise AttributeError
Err(vm.new_attribute_error("'property' object has no attribute '__name__'".to_owned()))
}
}

#[pygetset(name = "__name__", setter)]
fn name_setter(&self, value: PyObjectRef) {
*self.name.write() = Some(value);
}

fn doc_getter(&self) -> Option<PyObjectRef> {
self.doc.read().clone()
}
Expand Down
Loading