[bpo-28556] Minor fixes for typing module (#4710)
This commit is contained in:
parent
ca7562a7fe
commit
29bc193210
|
@ -37,6 +37,9 @@ except ImportError:
|
||||||
from test import mod_generics_cache
|
from test import mod_generics_cache
|
||||||
|
|
||||||
|
|
||||||
|
PY36 = sys.version_info[:2] >= (3, 6)
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase(TestCase):
|
class BaseTestCase(TestCase):
|
||||||
|
|
||||||
def assertIsSubclass(self, cls, class_or_tuple, msg=None):
|
def assertIsSubclass(self, cls, class_or_tuple, msg=None):
|
||||||
|
@ -633,6 +636,27 @@ class GenericTests(BaseTestCase):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
Generic[T, S, T]
|
Generic[T, S, T]
|
||||||
|
|
||||||
|
@skipUnless(PY36, "__init_subclass__ support required")
|
||||||
|
def test_init_subclass(self):
|
||||||
|
class X(typing.Generic[T]):
|
||||||
|
def __init_subclass__(cls, **kwargs):
|
||||||
|
super().__init_subclass__(**kwargs)
|
||||||
|
cls.attr = 42
|
||||||
|
class Y(X):
|
||||||
|
pass
|
||||||
|
self.assertEqual(Y.attr, 42)
|
||||||
|
with self.assertRaises(AttributeError):
|
||||||
|
X.attr
|
||||||
|
X.attr = 1
|
||||||
|
Y.attr = 2
|
||||||
|
class Z(Y):
|
||||||
|
pass
|
||||||
|
class W(X[int]):
|
||||||
|
pass
|
||||||
|
self.assertEqual(Y.attr, 2)
|
||||||
|
self.assertEqual(Z.attr, 42)
|
||||||
|
self.assertEqual(W.attr, 42)
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
self.assertEqual(repr(SimpleMapping),
|
self.assertEqual(repr(SimpleMapping),
|
||||||
__name__ + '.' + 'SimpleMapping')
|
__name__ + '.' + 'SimpleMapping')
|
||||||
|
@ -1080,6 +1104,30 @@ class GenericTests(BaseTestCase):
|
||||||
self.assertTrue(t is copy(t))
|
self.assertTrue(t is copy(t))
|
||||||
self.assertTrue(t is deepcopy(t))
|
self.assertTrue(t is deepcopy(t))
|
||||||
|
|
||||||
|
def test_copy_generic_instances(self):
|
||||||
|
T = TypeVar('T')
|
||||||
|
class C(Generic[T]):
|
||||||
|
def __init__(self, attr: T) -> None:
|
||||||
|
self.attr = attr
|
||||||
|
|
||||||
|
c = C(42)
|
||||||
|
self.assertEqual(copy(c).attr, 42)
|
||||||
|
self.assertEqual(deepcopy(c).attr, 42)
|
||||||
|
self.assertIsNot(copy(c), c)
|
||||||
|
self.assertIsNot(deepcopy(c), c)
|
||||||
|
c.attr = 1
|
||||||
|
self.assertEqual(copy(c).attr, 1)
|
||||||
|
self.assertEqual(deepcopy(c).attr, 1)
|
||||||
|
ci = C[int](42)
|
||||||
|
self.assertEqual(copy(ci).attr, 42)
|
||||||
|
self.assertEqual(deepcopy(ci).attr, 42)
|
||||||
|
self.assertIsNot(copy(ci), ci)
|
||||||
|
self.assertIsNot(deepcopy(ci), ci)
|
||||||
|
ci.attr = 1
|
||||||
|
self.assertEqual(copy(ci).attr, 1)
|
||||||
|
self.assertEqual(deepcopy(ci).attr, 1)
|
||||||
|
self.assertEqual(ci.__orig_class__, C[int])
|
||||||
|
|
||||||
def test_weakref_all(self):
|
def test_weakref_all(self):
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
things = [Any, Union[T, int], Callable[..., T], Tuple[Any, Any],
|
things = [Any, Union[T, int], Callable[..., T], Tuple[Any, Any],
|
||||||
|
@ -1580,8 +1628,6 @@ else:
|
||||||
asyncio = None
|
asyncio = None
|
||||||
AwaitableWrapper = AsyncIteratorWrapper = ACM = object
|
AwaitableWrapper = AsyncIteratorWrapper = ACM = object
|
||||||
|
|
||||||
PY36 = sys.version_info[:2] >= (3, 6)
|
|
||||||
|
|
||||||
PY36_TESTS = """
|
PY36_TESTS = """
|
||||||
from test import ann_module, ann_module2, ann_module3
|
from test import ann_module, ann_module2, ann_module3
|
||||||
from typing import AsyncContextManager
|
from typing import AsyncContextManager
|
||||||
|
|
|
@ -973,7 +973,8 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
|
||||||
# remove bare Generic from bases if there are other generic bases
|
# remove bare Generic from bases if there are other generic bases
|
||||||
if any(isinstance(b, GenericMeta) and b is not Generic for b in bases):
|
if any(isinstance(b, GenericMeta) and b is not Generic for b in bases):
|
||||||
bases = tuple(b for b in bases if b is not Generic)
|
bases = tuple(b for b in bases if b is not Generic)
|
||||||
namespace.update({'__origin__': origin, '__extra__': extra})
|
namespace.update({'__origin__': origin, '__extra__': extra,
|
||||||
|
'_gorg': None if not origin else origin._gorg})
|
||||||
self = super().__new__(cls, name, bases, namespace, _root=True)
|
self = super().__new__(cls, name, bases, namespace, _root=True)
|
||||||
super(GenericMeta, self).__setattr__('_gorg',
|
super(GenericMeta, self).__setattr__('_gorg',
|
||||||
self if not origin else origin._gorg)
|
self if not origin else origin._gorg)
|
||||||
|
@ -1160,17 +1161,12 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
|
||||||
# classes are supposed to be rare anyways.
|
# classes are supposed to be rare anyways.
|
||||||
return issubclass(instance.__class__, self)
|
return issubclass(instance.__class__, self)
|
||||||
|
|
||||||
def __copy__(self):
|
|
||||||
return self.__class__(self.__name__, self.__bases__,
|
|
||||||
_no_slots_copy(self.__dict__),
|
|
||||||
self.__parameters__, self.__args__, self.__origin__,
|
|
||||||
self.__extra__, self.__orig_bases__)
|
|
||||||
|
|
||||||
def __setattr__(self, attr, value):
|
def __setattr__(self, attr, value):
|
||||||
# We consider all the subscripted generics as proxies for original class
|
# We consider all the subscripted generics as proxies for original class
|
||||||
if (
|
if (
|
||||||
attr.startswith('__') and attr.endswith('__') or
|
attr.startswith('__') and attr.endswith('__') or
|
||||||
attr.startswith('_abc_')
|
attr.startswith('_abc_') or
|
||||||
|
self._gorg is None # The class is not fully created, see #typing/506
|
||||||
):
|
):
|
||||||
super(GenericMeta, self).__setattr__(attr, value)
|
super(GenericMeta, self).__setattr__(attr, value)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Two minor fixes for ``typing`` module: allow shallow copying instances of
|
||||||
|
generic classes, improve interaction of ``__init_subclass__`` with generics.
|
||||||
|
Original PRs by Ivan Levkivskyi.
|
Loading…
Reference in New Issue