Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit 043a8bc

Browse files
committed
Issue python#28556: merge 5 more typing changes from upstream (python#340, python#344, python#348, python#349, python#350) (3.5->3.6)
2 parents 5d37d63 + 83ec302 commit 043a8bc

File tree

2 files changed

+76
-12
lines changed

2 files changed

+76
-12
lines changed

Lib/test/test_typing.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from typing import Union, Optional
1313
from typing import Tuple, List, MutableMapping
1414
from typing import Callable
15-
from typing import Generic, ClassVar
15+
from typing import Generic, ClassVar, GenericMeta
1616
from typing import cast
1717
from typing import get_type_hints
1818
from typing import no_type_check, no_type_check_decorator
@@ -23,6 +23,7 @@
2323
from typing import Pattern, Match
2424
import abc
2525
import typing
26+
import weakref
2627
try:
2728
import collections.abc as collections_abc
2829
except ImportError:
@@ -281,6 +282,15 @@ def test_union_generalization(self):
281282
self.assertFalse(Union[str, typing.Iterable[int]] == typing.Iterable[int])
282283
self.assertTrue(Union[str, typing.Iterable] == typing.Iterable)
283284

285+
def test_union_compare_other(self):
286+
self.assertNotEqual(Union, object)
287+
self.assertNotEqual(Union, Any)
288+
self.assertNotEqual(ClassVar, Union)
289+
self.assertNotEqual(Optional, Union)
290+
self.assertNotEqual([None], Optional)
291+
self.assertNotEqual(Optional, typing.Mapping)
292+
self.assertNotEqual(Optional[typing.MutableMapping], Union)
293+
284294
def test_optional(self):
285295
o = Optional[int]
286296
u = Union[int, None]
@@ -718,6 +728,12 @@ class D(C, List[T][U][V]): ...
718728
self.assertEqual(C.__orig_bases__, (List[T][U][V],))
719729
self.assertEqual(D.__orig_bases__, (C, List[T][U][V]))
720730

731+
def test_subscript_meta(self):
732+
T = TypeVar('T')
733+
self.assertEqual(Type[GenericMeta], Type[GenericMeta])
734+
self.assertEqual(Union[T, int][GenericMeta], Union[GenericMeta, int])
735+
self.assertEqual(Callable[..., GenericMeta].__args__, (Ellipsis, GenericMeta))
736+
721737
def test_extended_generic_rules_eq(self):
722738
T = TypeVar('T')
723739
U = TypeVar('U')
@@ -896,6 +912,14 @@ class Node(Generic[T]): ...
896912
self.assertEqual(t, copy(t))
897913
self.assertEqual(t, deepcopy(t))
898914

915+
def test_weakref_all(self):
916+
T = TypeVar('T')
917+
things = [Any, Union[T, int], Callable[..., T], Tuple[Any, Any],
918+
Optional[List[int]], typing.Mapping[int, str],
919+
typing.re.Match[bytes], typing.Iterable['whatever']]
920+
for t in things:
921+
self.assertEqual(weakref.ref(t)(), t)
922+
899923
def test_parameterized_slots(self):
900924
T = TypeVar('T')
901925
class C(Generic[T]):
@@ -1918,7 +1942,9 @@ def test_basics(self):
19181942
self.assertEqual(jim.id, 1)
19191943
self.assertEqual(Emp.__name__, 'Emp')
19201944
self.assertEqual(Emp._fields, ('name', 'id'))
1921-
self.assertEqual(Emp._field_types, dict(name=str, id=int))
1945+
self.assertEqual(Emp.__annotations__,
1946+
collections.OrderedDict([('name', str), ('id', int)]))
1947+
self.assertIs(Emp._field_types, Emp.__annotations__)
19221948

19231949
@skipUnless(PY36, 'Python 3.6 required')
19241950
def test_annotation_usage(self):
@@ -1929,7 +1955,9 @@ def test_annotation_usage(self):
19291955
self.assertEqual(tim.cool, 9000)
19301956
self.assertEqual(CoolEmployee.__name__, 'CoolEmployee')
19311957
self.assertEqual(CoolEmployee._fields, ('name', 'cool'))
1932-
self.assertEqual(CoolEmployee._field_types, dict(name=str, cool=int))
1958+
self.assertEqual(CoolEmployee.__annotations__,
1959+
collections.OrderedDict(name=str, cool=int))
1960+
self.assertIs(CoolEmployee._field_types, CoolEmployee.__annotations__)
19331961

19341962
@skipUnless(PY36, 'Python 3.6 required')
19351963
def test_namedtuple_keyword_usage(self):
@@ -1939,7 +1967,8 @@ def test_namedtuple_keyword_usage(self):
19391967
self.assertEqual(nick.name, 'Nick')
19401968
self.assertEqual(LocalEmployee.__name__, 'LocalEmployee')
19411969
self.assertEqual(LocalEmployee._fields, ('name', 'age'))
1942-
self.assertEqual(LocalEmployee._field_types, dict(name=str, age=int))
1970+
self.assertEqual(LocalEmployee.__annotations__, dict(name=str, age=int))
1971+
self.assertIs(LocalEmployee._field_types, LocalEmployee.__annotations__)
19431972
with self.assertRaises(TypeError):
19441973
NamedTuple('Name', [('x', int)], y=str)
19451974
with self.assertRaises(TypeError):

Lib/typing.py

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727

2828
# ABCs (from collections.abc).
2929
'AbstractSet', # collections.abc.Set.
30+
'GenericMeta', # subclass of abc.ABCMeta and a metaclass
31+
# for 'Generic' and ABCs below.
3032
'ByteString',
3133
'Container',
3234
'Hashable',
@@ -145,7 +147,7 @@ def __repr__(self):
145147
class _TypingBase(metaclass=TypingMeta, _root=True):
146148
"""Internal indicator of special typing constructs."""
147149

148-
__slots__ = ()
150+
__slots__ = ('__weakref__',)
149151

150152
def __init__(self, *args, **kwds):
151153
pass
@@ -514,7 +516,7 @@ def _replace_arg(arg, tvars, args):
514516

515517
if tvars is None:
516518
tvars = []
517-
if hasattr(arg, '_subs_tree'):
519+
if hasattr(arg, '_subs_tree') and isinstance(arg, (GenericMeta, _TypingBase)):
518520
return arg._subs_tree(tvars, args)
519521
if isinstance(arg, TypeVar):
520522
for i, tvar in enumerate(tvars):
@@ -523,6 +525,16 @@ def _replace_arg(arg, tvars, args):
523525
return arg
524526

525527

528+
# Special typing constructs Union, Optional, Generic, Callable and Tuple
529+
# use three special attributes for internal bookkeeping of generic types:
530+
# * __parameters__ is a tuple of unique free type parameters of a generic
531+
# type, for example, Dict[T, T].__parameters__ == (T,);
532+
# * __origin__ keeps a reference to a type that was subscripted,
533+
# e.g., Union[T, int].__origin__ == Union;
534+
# * __args__ is a tuple of all arguments used in subscripting,
535+
# e.g., Dict[T, int].__args__ == (T, int).
536+
537+
526538
def _subs_tree(cls, tvars=None, args=None):
527539
"""An internal helper function: calculate substitution tree
528540
for generic cls after replacing its type parameters with
@@ -757,9 +769,12 @@ def _subs_tree(self, tvars=None, args=None):
757769
return (Union,) + tree_args
758770

759771
def __eq__(self, other):
760-
if not isinstance(other, _Union):
772+
if isinstance(other, _Union):
773+
return self.__tree_hash__ == other.__tree_hash__
774+
elif self is not Union:
761775
return self._subs_tree() == other
762-
return self.__tree_hash__ == other.__tree_hash__
776+
else:
777+
return self is other
763778

764779
def __hash__(self):
765780
return self.__tree_hash__
@@ -883,10 +898,26 @@ def _no_slots_copy(dct):
883898

884899

885900
class GenericMeta(TypingMeta, abc.ABCMeta):
886-
"""Metaclass for generic types."""
901+
"""Metaclass for generic types.
902+
903+
This is a metaclass for typing.Generic and generic ABCs defined in
904+
typing module. User defined subclasses of GenericMeta can override
905+
__new__ and invoke super().__new__. Note that GenericMeta.__new__
906+
has strict rules on what is allowed in its bases argument:
907+
* plain Generic is disallowed in bases;
908+
* Generic[...] should appear in bases at most once;
909+
* if Generic[...] is present, then it should list all type variables
910+
that appear in other bases.
911+
In addition, type of all generic bases is erased, e.g., C[int] is
912+
stripped to plain C.
913+
"""
887914

888915
def __new__(cls, name, bases, namespace,
889916
tvars=None, args=None, origin=None, extra=None, orig_bases=None):
917+
"""Create a new generic class. GenericMeta.__new__ accepts
918+
keyword arguments that are used for internal bookkeeping, therefore
919+
an override should pass unused keyword arguments to super().
920+
"""
890921
if tvars is not None:
891922
# Called from __getitem__() below.
892923
assert origin is not None
@@ -1906,7 +1937,9 @@ def _make_nmtuple(name, types):
19061937
msg = "NamedTuple('Name', [(f0, t0), (f1, t1), ...]); each t must be a type"
19071938
types = [(n, _type_check(t, msg)) for n, t in types]
19081939
nm_tpl = collections.namedtuple(name, [n for n, t in types])
1909-
nm_tpl._field_types = dict(types)
1940+
# Prior to PEP 526, only _field_types attribute was assigned.
1941+
# Now, both __annotations__ and _field_types are used to maintain compatibility.
1942+
nm_tpl.__annotations__ = nm_tpl._field_types = collections.OrderedDict(types)
19101943
try:
19111944
nm_tpl.__module__ = sys._getframe(2).f_globals.get('__name__', '__main__')
19121945
except (AttributeError, ValueError):
@@ -1941,8 +1974,10 @@ class Employee(NamedTuple):
19411974
19421975
Employee = collections.namedtuple('Employee', ['name', 'id'])
19431976
1944-
The resulting class has one extra attribute: _field_types,
1945-
giving a dict mapping field names to types. (The field names
1977+
The resulting class has extra __annotations__ and _field_types
1978+
attributes, giving an ordered dict mapping field names to types.
1979+
__annotations__ should be preferred, while _field_types
1980+
is kept to maintain pre PEP 526 compatibility. (The field names
19461981
are in the _fields attribute, which is part of the namedtuple
19471982
API.) Alternative equivalent keyword syntax is also accepted::
19481983

0 commit comments

Comments
 (0)