mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Update abc module to CPython 3.10.0
This commit is contained in:
1 parent
c060f9973d
commit
1b227f8f89
2 files changed
+254
-6
No files matched your search
Vendored
+66
-3
@@ -28,7 +28,14 @@ def abstractmethod(funcobj):
|
||||
class abstractclassmethod(classmethod):
|
||||
"""A decorator indicating abstract classmethods.
|
||||
|
||||
Deprecated, use 'classmethod' with 'abstractmethod' instead.
|
||||
Deprecated, use 'classmethod' with 'abstractmethod' instead:
|
||||
|
||||
class C(ABC):
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def my_abstract_classmethod(cls, ...):
|
||||
...
|
||||
|
||||
"""
|
||||
|
||||
__isabstractmethod__ = True
|
||||
@@ -41,7 +48,14 @@ class abstractclassmethod(classmethod):
|
||||
class abstractstaticmethod(staticmethod):
|
||||
"""A decorator indicating abstract staticmethods.
|
||||
|
||||
Deprecated, use 'staticmethod' with 'abstractmethod' instead.
|
||||
Deprecated, use 'staticmethod' with 'abstractmethod' instead:
|
||||
|
||||
class C(ABC):
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def my_abstract_staticmethod(...):
|
||||
...
|
||||
|
||||
"""
|
||||
|
||||
__isabstractmethod__ = True
|
||||
@@ -54,7 +68,14 @@ class abstractstaticmethod(staticmethod):
|
||||
class abstractproperty(property):
|
||||
"""A decorator indicating abstract properties.
|
||||
|
||||
Deprecated, use 'property' with 'abstractmethod' instead.
|
||||
Deprecated, use 'property' with 'abstractmethod' instead:
|
||||
|
||||
class C(ABC):
|
||||
@property
|
||||
@abstractmethod
|
||||
def my_abstract_property(self):
|
||||
...
|
||||
|
||||
"""
|
||||
|
||||
__isabstractmethod__ = True
|
||||
@@ -64,6 +85,10 @@ try:
|
||||
from _abc import (get_cache_token, _abc_init, _abc_register,
|
||||
_abc_instancecheck, _abc_subclasscheck, _get_dump,
|
||||
_reset_registry, _reset_caches)
|
||||
# TODO: RUSTPYTHON missing _abc module implementation.
|
||||
except ModuleNotFoundError:
|
||||
from _py_abc import ABCMeta, get_cache_token
|
||||
ABCMeta.__module__ = 'abc'
|
||||
except ImportError:
|
||||
from _py_abc import ABCMeta, get_cache_token
|
||||
ABCMeta.__module__ = 'abc'
|
||||
@@ -122,6 +147,44 @@ else:
|
||||
_reset_caches(cls)
|
||||
|
||||
|
||||
def update_abstractmethods(cls):
|
||||
"""Recalculate the set of abstract methods of an abstract class.
|
||||
|
||||
If a class has had one of its abstract methods implemented after the
|
||||
class was created, the method will not be considered implemented until
|
||||
this function is called. Alternatively, if a new abstract method has been
|
||||
added to the class, it will only be considered an abstract method of the
|
||||
class after this function is called.
|
||||
|
||||
This function should be called before any use is made of the class,
|
||||
usually in class decorators that add methods to the subject class.
|
||||
|
||||
Returns cls, to allow usage as a class decorator.
|
||||
|
||||
If cls is not an instance of ABCMeta, does nothing.
|
||||
"""
|
||||
if not hasattr(cls, '__abstractmethods__'):
|
||||
# We check for __abstractmethods__ here because cls might by a C
|
||||
# implementation or a python implementation (especially during
|
||||
# testing), and we want to handle both cases.
|
||||
return cls
|
||||
|
||||
abstracts = set()
|
||||
# Check the existing abstract methods of the parents, keep only the ones
|
||||
# that are not implemented.
|
||||
for scls in cls.__bases__:
|
||||
for name in getattr(scls, '__abstractmethods__', ()):
|
||||
value = getattr(cls, name, None)
|
||||
if getattr(value, "__isabstractmethod__", False):
|
||||
abstracts.add(name)
|
||||
# Also add any other newly added abstract methods.
|
||||
for name, value in cls.__dict__.items():
|
||||
if getattr(value, "__isabstractmethod__", False):
|
||||
abstracts.add(name)
|
||||
cls.__abstractmethods__ = frozenset(abstracts)
|
||||
return cls
|
||||
|
||||
|
||||
class ABC(metaclass=ABCMeta):
|
||||
"""Helper class that provides a standard way to create an ABC using
|
||||
inheritance.
|
||||
|
||||
Vendored
+188
-3
@@ -157,8 +157,25 @@ 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_object_new_with_one_abstractmethod(self):
|
||||
class C(metaclass=abc_ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def method_one(self):
|
||||
pass
|
||||
msg = r"class C with abstract method method_one"
|
||||
self.assertRaisesRegex(TypeError, msg, C)
|
||||
|
||||
def test_object_new_with_many_abstractmethods(self):
|
||||
class C(metaclass=abc_ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def method_one(self):
|
||||
pass
|
||||
@abc.abstractmethod
|
||||
def method_two(self):
|
||||
pass
|
||||
msg = r"class C with abstract methods method_one, method_two"
|
||||
self.assertRaisesRegex(TypeError, msg, C)
|
||||
|
||||
def test_abstractmethod_integration(self):
|
||||
for abstractthing in [abc.abstractmethod, abc.abstractproperty,
|
||||
abc.abstractclassmethod,
|
||||
@@ -219,6 +236,7 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
|
||||
bar.__isabstractmethod__ = NotBool()
|
||||
foo = property(bar)
|
||||
|
||||
|
||||
def test_customdescriptors_with_abstractmethod(self):
|
||||
class Descriptor:
|
||||
def __init__(self, fget, fset=None):
|
||||
@@ -318,7 +336,7 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
|
||||
token_old = abc_get_cache_token()
|
||||
A.register(B)
|
||||
token_new = abc_get_cache_token()
|
||||
self.assertNotEqual(token_old, token_new)
|
||||
self.assertGreater(token_new, token_old)
|
||||
self.assertTrue(isinstance(b, A))
|
||||
self.assertTrue(isinstance(b, (A,)))
|
||||
|
||||
@@ -451,6 +469,24 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
|
||||
with self.assertRaisesRegex(Exception, exc_msg):
|
||||
issubclass(int, S)
|
||||
|
||||
def test_subclasshook(self):
|
||||
class A(metaclass=abc.ABCMeta):
|
||||
@classmethod
|
||||
def __subclasshook__(cls, C):
|
||||
if cls is A:
|
||||
return 'foo' in C.__dict__
|
||||
return NotImplemented
|
||||
self.assertFalse(issubclass(A, A))
|
||||
self.assertFalse(issubclass(A, (A,)))
|
||||
class B:
|
||||
foo = 42
|
||||
self.assertTrue(issubclass(B, A))
|
||||
self.assertTrue(issubclass(B, (A,)))
|
||||
class C:
|
||||
spam = 42
|
||||
self.assertFalse(issubclass(C, A))
|
||||
self.assertFalse(issubclass(C, (A,)))
|
||||
|
||||
def test_all_new_methods_are_called(self):
|
||||
class A(metaclass=abc_ABCMeta):
|
||||
pass
|
||||
@@ -480,6 +516,155 @@ def test_factory(abc_ABCMeta, abc_get_cache_token):
|
||||
pass
|
||||
self.assertEqual(C.__class__, abc_ABCMeta)
|
||||
|
||||
def test_update_del(self):
|
||||
class A(metaclass=abc_ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
del A.foo
|
||||
self.assertEqual(A.__abstractmethods__, {'foo'})
|
||||
self.assertFalse(hasattr(A, 'foo'))
|
||||
|
||||
abc.update_abstractmethods(A)
|
||||
|
||||
self.assertEqual(A.__abstractmethods__, set())
|
||||
A()
|
||||
|
||||
|
||||
def test_update_new_abstractmethods(self):
|
||||
class A(metaclass=abc_ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def bar(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def updated_foo(self):
|
||||
pass
|
||||
|
||||
A.foo = updated_foo
|
||||
abc.update_abstractmethods(A)
|
||||
self.assertEqual(A.__abstractmethods__, {'foo', 'bar'})
|
||||
msg = "class A with abstract methods bar, foo"
|
||||
self.assertRaisesRegex(TypeError, msg, A)
|
||||
|
||||
def test_update_implementation(self):
|
||||
class A(metaclass=abc_ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
class B(A):
|
||||
pass
|
||||
|
||||
msg = "class B with abstract method foo"
|
||||
self.assertRaisesRegex(TypeError, msg, B)
|
||||
self.assertEqual(B.__abstractmethods__, {'foo'})
|
||||
|
||||
B.foo = lambda self: None
|
||||
|
||||
abc.update_abstractmethods(B)
|
||||
|
||||
B()
|
||||
self.assertEqual(B.__abstractmethods__, set())
|
||||
|
||||
def test_update_as_decorator(self):
|
||||
class A(metaclass=abc_ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
def class_decorator(cls):
|
||||
cls.foo = lambda self: None
|
||||
return cls
|
||||
|
||||
@abc.update_abstractmethods
|
||||
@class_decorator
|
||||
class B(A):
|
||||
pass
|
||||
|
||||
B()
|
||||
self.assertEqual(B.__abstractmethods__, set())
|
||||
|
||||
def test_update_non_abc(self):
|
||||
class A:
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def updated_foo(self):
|
||||
pass
|
||||
|
||||
A.foo = updated_foo
|
||||
abc.update_abstractmethods(A)
|
||||
A()
|
||||
self.assertFalse(hasattr(A, '__abstractmethods__'))
|
||||
|
||||
def test_update_del_implementation(self):
|
||||
class A(metaclass=abc_ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
class B(A):
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
B()
|
||||
|
||||
del B.foo
|
||||
|
||||
abc.update_abstractmethods(B)
|
||||
|
||||
msg = "class B with abstract method foo"
|
||||
self.assertRaisesRegex(TypeError, msg, B)
|
||||
|
||||
def test_update_layered_implementation(self):
|
||||
class A(metaclass=abc_ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
class B(A):
|
||||
pass
|
||||
|
||||
class C(B):
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
C()
|
||||
|
||||
del C.foo
|
||||
|
||||
abc.update_abstractmethods(C)
|
||||
|
||||
msg = "class C with abstract method foo"
|
||||
self.assertRaisesRegex(TypeError, msg, C)
|
||||
|
||||
def test_update_multi_inheritance(self):
|
||||
class A(metaclass=abc_ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
class B(metaclass=abc_ABCMeta):
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
class C(B, A):
|
||||
@abc.abstractmethod
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
self.assertEqual(C.__abstractmethods__, {'foo'})
|
||||
|
||||
del C.foo
|
||||
|
||||
abc.update_abstractmethods(C)
|
||||
|
||||
self.assertEqual(C.__abstractmethods__, set())
|
||||
|
||||
C()
|
||||
|
||||
|
||||
class TestABCWithInitSubclass(unittest.TestCase):
|
||||
def test_works_with_init_subclass(self):
|
||||
|
||||
Reference in new issue
Block a user