Skip to content

Commit

Permalink
Update typing.py from python/typing (3.6.1 PyPI release) (python#3059)
Browse files Browse the repository at this point in the history
  • Loading branch information
ambv authored and gvanrossum committed Mar 26, 2017
1 parent 1ffa0c6 commit eb1eb0d
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 9 deletions.
39 changes: 35 additions & 4 deletions lib-typing/2.7/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,6 @@ def test_cannot_instantiate(self):
with self.assertRaises(TypeError):
type(Any)()

def test_cannot_subscript(self):
with self.assertRaises(TypeError):
Any[int]

def test_any_is_subclass(self):
# These expressions must simply not fail.
typing.Match[Any]
Expand Down Expand Up @@ -642,6 +638,41 @@ class C(B[int]):
c.bar = 'abc'
self.assertEqual(c.__dict__, {'bar': 'abc'})

def test_subscripted_generics_as_proxies(self):
T = TypeVar('T')
class C(Generic[T]):
x = 'def'
self.assertEqual(C[int].x, 'def')
self.assertEqual(C[C[int]].x, 'def')
C[C[int]].x = 'changed'
self.assertEqual(C.x, 'changed')
self.assertEqual(C[str].x, 'changed')
C[List[str]].z = 'new'
self.assertEqual(C.z, 'new')
self.assertEqual(C[Tuple[int]].z, 'new')

self.assertEqual(C().x, 'changed')
self.assertEqual(C[Tuple[str]]().z, 'new')

class D(C[T]):
pass
self.assertEqual(D[int].x, 'changed')
self.assertEqual(D.z, 'new')
D.z = 'from derived z'
D[int].x = 'from derived x'
self.assertEqual(C.x, 'changed')
self.assertEqual(C[int].z, 'new')
self.assertEqual(D.x, 'from derived x')
self.assertEqual(D[str].z, 'from derived z')

def test_abc_registry_kept(self):
T = TypeVar('T')
class C(Generic[T]): pass
C.register(int)
self.assertIsInstance(1, C)
C[int]
self.assertIsInstance(1, C)

def test_false_subclasses(self):
class MyMapping(MutableMapping[str, str]): pass
self.assertNotIsInstance({}, MyMapping)
Expand Down
12 changes: 11 additions & 1 deletion lib-typing/2.7/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1243,6 +1243,16 @@ def __copy__(self):
self.__parameters__, self.__args__, self.__origin__,
self.__extra__, self.__orig_bases__)

def __setattr__(self, attr, value):
# We consider all the subscripted genrics as proxies for original class
if (
attr.startswith('__') and attr.endswith('__') or
attr.startswith('_abc_')
):
super(GenericMeta, self).__setattr__(attr, value)
else:
super(GenericMeta, _gorg(self)).__setattr__(attr, value)


# Prevent checks for Generic to crash when defining Generic.
Generic = None
Expand Down Expand Up @@ -1900,7 +1910,7 @@ def NamedTuple(typename, fields):
Usage::
Employee = typing.NamedTuple('Employee', [('name', str), 'id', int)])
Employee = typing.NamedTuple('Employee', [('name', str), ('id', int)])
This is equivalent to::
Expand Down
39 changes: 35 additions & 4 deletions lib-typing/3.2/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,6 @@ def test_cannot_instantiate(self):
with self.assertRaises(TypeError):
type(Any)()

def test_cannot_subscript(self):
with self.assertRaises(TypeError):
Any[int]

def test_any_works_with_alias(self):
# These expressions must simply not fail.
typing.Match[Any]
Expand Down Expand Up @@ -674,6 +670,41 @@ class C(B[int]):
c.bar = 'abc'
self.assertEqual(c.__dict__, {'bar': 'abc'})

def test_subscripted_generics_as_proxies(self):
T = TypeVar('T')
class C(Generic[T]):
x = 'def'
self.assertEqual(C[int].x, 'def')
self.assertEqual(C[C[int]].x, 'def')
C[C[int]].x = 'changed'
self.assertEqual(C.x, 'changed')
self.assertEqual(C[str].x, 'changed')
C[List[str]].z = 'new'
self.assertEqual(C.z, 'new')
self.assertEqual(C[Tuple[int]].z, 'new')

self.assertEqual(C().x, 'changed')
self.assertEqual(C[Tuple[str]]().z, 'new')

class D(C[T]):
pass
self.assertEqual(D[int].x, 'changed')
self.assertEqual(D.z, 'new')
D.z = 'from derived z'
D[int].x = 'from derived x'
self.assertEqual(C.x, 'changed')
self.assertEqual(C[int].z, 'new')
self.assertEqual(D.x, 'from derived x')
self.assertEqual(D[str].z, 'from derived z')

def test_abc_registry_kept(self):
T = TypeVar('T')
class C(Generic[T]): ...
C.register(int)
self.assertIsInstance(1, C)
C[int]
self.assertIsInstance(1, C)

def test_false_subclasses(self):
class MyMapping(MutableMapping[str, str]): pass
self.assertNotIsInstance({}, MyMapping)
Expand Down
10 changes: 10 additions & 0 deletions lib-typing/3.2/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,16 @@ def __copy__(self):
self.__parameters__, self.__args__, self.__origin__,
self.__extra__, self.__orig_bases__)

def __setattr__(self, attr, value):
# We consider all the subscripted genrics as proxies for original class
if (
attr.startswith('__') and attr.endswith('__') or
attr.startswith('_abc_')
):
super(GenericMeta, self).__setattr__(attr, value)
else:
super(GenericMeta, _gorg(self)).__setattr__(attr, value)


# Prevent checks for Generic to crash when defining Generic.
Generic = None
Expand Down

0 comments on commit eb1eb0d

Please sign in to comment.