forked from Rust-related/RustPython
Fix __isabstractmethod__ for class/static methods and properties
Includes a minor departure from CPython implementation of inspect.isabstract because TPFLAGS_IS_ABSTRACT is not set in obj.__flags__.
This commit is contained in:
6
Lib/inspect.py
vendored
6
Lib/inspect.py
vendored
@@ -300,16 +300,16 @@ def isroutine(object):
|
||||
|
||||
def isabstract(object):
|
||||
"""Return true if the object is an abstract base class (ABC)."""
|
||||
# TODO: RUSTPYTHON
|
||||
# TPFLAGS_IS_ABSTRACT is not being set for abstract classes, so this implementation differs from CPython.
|
||||
if not isinstance(object, type):
|
||||
return False
|
||||
if object.__flags__ & TPFLAGS_IS_ABSTRACT:
|
||||
return True
|
||||
if not issubclass(type(object), abc.ABCMeta):
|
||||
return False
|
||||
if hasattr(object, '__abstractmethods__'):
|
||||
# It looks like ABCMeta.__new__ has finished running;
|
||||
# TPFLAGS_IS_ABSTRACT should have been accurate.
|
||||
return False
|
||||
return bool(getattr(object, '__abstractmethods__'))
|
||||
# It looks like ABCMeta.__new__ has not finished running yet; we're
|
||||
# probably in __init_subclass__. We'll look for abstractmethods manually.
|
||||
for name, value in object.__dict__.items():
|
||||
|
||||
12
Lib/test/test_abc.py
vendored
12
Lib/test/test_abc.py
vendored
@@ -71,8 +71,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
|
||||
|
||||
class TestABC(unittest.TestCase):
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_ABC_helper(self):
|
||||
# create an ABC using the helper class and perform basic checks
|
||||
class C(abc.ABC):
|
||||
@@ -93,8 +91,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
|
||||
def bar(self): pass
|
||||
self.assertFalse(hasattr(bar, "__isabstractmethod__"))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_abstractproperty_basics(self):
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
@@ -113,8 +109,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
|
||||
def foo(self): return super().foo
|
||||
self.assertEqual(D().foo, 3)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_abstractclassmethod_basics(self):
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
@@ -135,8 +129,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
|
||||
self.assertEqual(D.foo(), 'D')
|
||||
self.assertEqual(D().foo(), 'D')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_abstractstaticmethod_basics(self):
|
||||
@staticmethod
|
||||
@abc.abstractmethod
|
||||
@@ -157,8 +149,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
|
||||
self.assertEqual(D.foo(), 4)
|
||||
self.assertEqual(D().foo(), 4)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_abstractmethod_integration(self):
|
||||
for abstractthing in [abc.abstractmethod, abc.abstractproperty,
|
||||
abc.abstractclassmethod,
|
||||
@@ -187,8 +177,6 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
|
||||
self.assertRaises(TypeError, F) # because bar is abstract now
|
||||
self.assertTrue(isabstract(F))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_descriptors_with_abstractmethod(self):
|
||||
class C(metaclass=abc_ABCMeta):
|
||||
@property
|
||||
|
||||
@@ -76,6 +76,20 @@ impl PyClassMethod {
|
||||
fn func(&self) -> PyObjectRef {
|
||||
self.callable.clone()
|
||||
}
|
||||
|
||||
#[pyproperty(magic)]
|
||||
fn isabstractmethod(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
match vm.get_attribute_opt(self.callable.clone(), "__isabstractmethod__") {
|
||||
Ok(Some(is_abstract)) => is_abstract,
|
||||
_ => vm.ctx.new_bool(false).into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproperty(magic, setter)]
|
||||
fn set_isabstractmethod(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
self.callable.set_attr("__isabstractmethod__", value, vm)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn init(context: &PyContext) {
|
||||
|
||||
@@ -217,6 +217,32 @@ impl PyProperty {
|
||||
}
|
||||
.into_ref_with_type(vm, TypeProtocol::clone_class(&zelf))
|
||||
}
|
||||
|
||||
#[pyproperty(magic)]
|
||||
fn isabstractmethod(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let getter_abstract = match self.getter.read().to_owned() {
|
||||
Some(getter) => getter
|
||||
.get_attr("__isabstractmethod__", vm)
|
||||
.unwrap_or(vm.ctx.new_bool(false).into()),
|
||||
_ => vm.ctx.new_bool(false).into(),
|
||||
};
|
||||
let setter_abstract = match self.setter.read().to_owned() {
|
||||
Some(setter) => setter
|
||||
.get_attr("__isabstractmethod__", vm)
|
||||
.unwrap_or(vm.ctx.new_bool(false).into()),
|
||||
_ => vm.ctx.new_bool(false).into(),
|
||||
};
|
||||
vm._or(&setter_abstract, &getter_abstract)
|
||||
.unwrap_or(vm.ctx.new_bool(false).into())
|
||||
}
|
||||
|
||||
#[pyproperty(magic, setter)]
|
||||
fn set_isabstractmethod(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if let Some(getter) = self.getter.read().to_owned() {
|
||||
getter.set_attr("__isabstractmethod__", value, vm)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn init(context: &PyContext) {
|
||||
|
||||
@@ -60,7 +60,21 @@ impl PyStaticMethod {
|
||||
}
|
||||
|
||||
#[pyimpl(with(GetDescriptor, Constructor), flags(BASETYPE, HAS_DICT))]
|
||||
impl PyStaticMethod {}
|
||||
impl PyStaticMethod {
|
||||
#[pyproperty(magic)]
|
||||
fn isabstractmethod(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
match vm.get_attribute_opt(self.callable.clone(), "__isabstractmethod__") {
|
||||
Ok(Some(is_abstract)) => is_abstract,
|
||||
_ => vm.ctx.new_bool(false).into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproperty(magic, setter)]
|
||||
fn set_isabstractmethod(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
self.callable.set_attr("__isabstractmethod__", value, vm)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
PyStaticMethod::extend_class(context, &context.types.staticmethod_type);
|
||||
|
||||
Reference in New Issue
Block a user