Skip to content

Commit 6e4e9e9

Browse files
committed
Fix property.isabstractmethod
1 parent 0d7ed0e commit 6e4e9e9

2 files changed

Lines changed: 51 additions & 24 deletions

File tree

Lib/test/test_property.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,6 @@ def test_property_getter_doc_override(self):
128128
self.assertEqual(newgetter.spam, 8)
129129
self.assertEqual(newgetter.__class__.spam.__doc__, "new docstring")
130130

131-
# TODO: RUSTPYTHON
132-
@unittest.expectedFailure
133131
def test_property___isabstractmethod__descriptor(self):
134132
for val in (True, False, [], [1], '', '1'):
135133
class C(object):
@@ -258,8 +256,6 @@ def spam(self):
258256
else:
259257
raise Exception("AttributeError not raised")
260258

261-
# TODO: RUSTPYTHON
262-
@unittest.expectedFailure
263259
@unittest.skipIf(sys.flags.optimize >= 2,
264260
"Docstrings are omitted with -O2 and above")
265261
def test_docstring_copy(self):
@@ -272,8 +268,6 @@ def spam(self):
272268
Foo.spam.__doc__,
273269
"spam wrapped in property subclass")
274270

275-
# TODO: RUSTPYTHON
276-
@unittest.expectedFailure
277271
@unittest.skipIf(sys.flags.optimize >= 2,
278272
"Docstrings are omitted with -O2 and above")
279273
def test_property_setter_copies_getter_docstring(self):
@@ -307,8 +301,6 @@ def spam(self, value):
307301
FooSub.spam.__doc__,
308302
"spam wrapped in property subclass")
309303

310-
# TODO: RUSTPYTHON
311-
@unittest.expectedFailure
312304
@unittest.skipIf(sys.flags.optimize >= 2,
313305
"Docstrings are omitted with -O2 and above")
314306
def test_property_new_getter_new_docstring(self):

vm/src/builtins/property.rs

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -255,21 +255,38 @@ impl PyProperty {
255255
}
256256

257257
#[pygetset(magic)]
258-
fn isabstractmethod(&self, vm: &VirtualMachine) -> PyObjectRef {
259-
let getter_abstract = match self.getter.read().to_owned() {
260-
Some(getter) => getter
261-
.get_attr("__isabstractmethod__", vm)
262-
.unwrap_or_else(|_| vm.ctx.new_bool(false).into()),
263-
_ => vm.ctx.new_bool(false).into(),
264-
};
265-
let setter_abstract = match self.setter.read().to_owned() {
266-
Some(setter) => setter
267-
.get_attr("__isabstractmethod__", vm)
268-
.unwrap_or_else(|_| vm.ctx.new_bool(false).into()),
269-
_ => vm.ctx.new_bool(false).into(),
270-
};
271-
vm._or(&setter_abstract, &getter_abstract)
272-
.unwrap_or_else(|_| vm.ctx.new_bool(false).into())
258+
fn isabstractmethod(&self, vm: &VirtualMachine) -> PyResult {
259+
// Check getter first
260+
if let Some(getter) = self.getter.read().as_ref() {
261+
if let Ok(isabstract) = getter.get_attr("__isabstractmethod__", vm) {
262+
let is_true = isabstract.try_to_bool(vm)?;
263+
if is_true {
264+
return Ok(vm.ctx.new_bool(true).into());
265+
}
266+
}
267+
}
268+
269+
// Check setter
270+
if let Some(setter) = self.setter.read().as_ref() {
271+
if let Ok(isabstract) = setter.get_attr("__isabstractmethod__", vm) {
272+
let is_true = isabstract.try_to_bool(vm)?;
273+
if is_true {
274+
return Ok(vm.ctx.new_bool(true).into());
275+
}
276+
}
277+
}
278+
279+
// Check deleter
280+
if let Some(deleter) = self.deleter.read().as_ref() {
281+
if let Ok(isabstract) = deleter.get_attr("__isabstractmethod__", vm) {
282+
let is_true = isabstract.try_to_bool(vm)?;
283+
if is_true {
284+
return Ok(vm.ctx.new_bool(true).into());
285+
}
286+
}
287+
}
288+
289+
Ok(vm.ctx.new_bool(false).into())
273290
}
274291

275292
#[pygetset(magic, setter)]
@@ -329,7 +346,25 @@ impl Initializer for PyProperty {
329346
}
330347
};
331348

332-
*zelf.doc.write() = doc;
349+
// Check if this is a property subclass
350+
let is_exact_property = zelf.class().is(vm.ctx.types.property_type);
351+
352+
if is_exact_property {
353+
// For exact property type, store doc in the field
354+
*zelf.doc.write() = doc;
355+
} else {
356+
// For property subclass, set __doc__ as an attribute
357+
let doc_to_set = doc.unwrap_or_else(|| vm.ctx.none());
358+
match zelf.as_object().set_attr("__doc__", doc_to_set, vm) {
359+
Ok(()) => {}
360+
Err(e) if !getter_doc && e.class().is(vm.ctx.exceptions.attribute_error) => {
361+
// Silently ignore AttributeError for backwards compatibility
362+
// (only when not using getter_doc)
363+
}
364+
Err(e) => return Err(e),
365+
}
366+
}
367+
333368
zelf.getter_doc.store(getter_doc, Ordering::Relaxed);
334369

335370
Ok(())

0 commit comments

Comments
 (0)