Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
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
45 changes: 35 additions & 10 deletions vm/src/builtins/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,30 @@ impl GetDescriptor for PyProperty {
#[pyclass(with(Constructor, Initializer, GetDescriptor), flags(BASETYPE))]
impl PyProperty {
// Helper method to get property name
fn get_property_name(&self, vm: &VirtualMachine) -> Option<PyObjectRef> {
// Returns the name if available, None if not found, or propagates errors
fn get_property_name(&self, vm: &VirtualMachine) -> PyResult<Option<PyObjectRef>> {
// First check if name was set via __set_name__
if let Some(name) = self.name.read().as_ref() {
return Some(name.clone());
return Ok(Some(name.clone()));
}

// Otherwise try to get __name__ from getter
if let Some(getter) = self.getter.read().as_ref()
&& let Ok(name) = getter.get_attr("__name__", vm)
{
return Some(name);
}
let getter = self.getter.read();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an extra variable because a temporary value issue prevented a single-line implementation.

let Some(getter) = getter.as_ref() else {
return Ok(None);
};

None
match getter.get_attr("__name__", vm) {
Ok(name) => Ok(Some(name)),
Err(e) => {
// If it's an AttributeError from the getter, return None
// Otherwise, propagate the original exception (e.g., RuntimeError)
if e.class().is(vm.ctx.exceptions.attribute_error) {
Ok(None)
} else {
Err(e)
}
}
}
}

// Descriptor methods
Expand Down Expand Up @@ -143,6 +153,21 @@ impl PyProperty {
self.deleter.read().clone()
}

#[pygetset(name = "__name__")]
fn name_getter(&self, vm: &VirtualMachine) -> PyResult {
match self.get_property_name(vm)? {
Some(name) => Ok(name),
None => 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 Expand Up @@ -288,7 +313,7 @@ impl PyProperty {
error_type: &str,
vm: &VirtualMachine,
) -> PyResult<String> {
let prop_name = self.get_property_name(vm);
let prop_name = self.get_property_name(vm)?;
let obj_type = obj.class();
let qualname = obj_type.__qualname__(vm);

Expand Down