27
27
28
28
# ABCs (from collections.abc).
29
29
'AbstractSet' , # collections.abc.Set.
30
+ 'GenericMeta' , # subclass of abc.ABCMeta and a metaclass
31
+ # for 'Generic' and ABCs below.
30
32
'ByteString' ,
31
33
'Container' ,
32
34
'Hashable' ,
@@ -145,7 +147,7 @@ def __repr__(self):
145
147
class _TypingBase (metaclass = TypingMeta , _root = True ):
146
148
"""Internal indicator of special typing constructs."""
147
149
148
- __slots__ = ()
150
+ __slots__ = ('__weakref__' , )
149
151
150
152
def __init__ (self , * args , ** kwds ):
151
153
pass
@@ -514,7 +516,7 @@ def _replace_arg(arg, tvars, args):
514
516
515
517
if tvars is None :
516
518
tvars = []
517
- if hasattr (arg , '_subs_tree' ):
519
+ if hasattr (arg , '_subs_tree' ) and isinstance ( arg , ( GenericMeta , _TypingBase )) :
518
520
return arg ._subs_tree (tvars , args )
519
521
if isinstance (arg , TypeVar ):
520
522
for i , tvar in enumerate (tvars ):
@@ -523,6 +525,16 @@ def _replace_arg(arg, tvars, args):
523
525
return arg
524
526
525
527
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
+
526
538
def _subs_tree (cls , tvars = None , args = None ):
527
539
"""An internal helper function: calculate substitution tree
528
540
for generic cls after replacing its type parameters with
@@ -757,9 +769,12 @@ def _subs_tree(self, tvars=None, args=None):
757
769
return (Union ,) + tree_args
758
770
759
771
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 :
761
775
return self ._subs_tree () == other
762
- return self .__tree_hash__ == other .__tree_hash__
776
+ else :
777
+ return self is other
763
778
764
779
def __hash__ (self ):
765
780
return self .__tree_hash__
@@ -883,10 +898,26 @@ def _no_slots_copy(dct):
883
898
884
899
885
900
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
+ """
887
914
888
915
def __new__ (cls , name , bases , namespace ,
889
916
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
+ """
890
921
if tvars is not None :
891
922
# Called from __getitem__() below.
892
923
assert origin is not None
@@ -1906,7 +1937,9 @@ def _make_nmtuple(name, types):
1906
1937
msg = "NamedTuple('Name', [(f0, t0), (f1, t1), ...]); each t must be a type"
1907
1938
types = [(n , _type_check (t , msg )) for n , t in types ]
1908
1939
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 )
1910
1943
try :
1911
1944
nm_tpl .__module__ = sys ._getframe (2 ).f_globals .get ('__name__' , '__main__' )
1912
1945
except (AttributeError , ValueError ):
@@ -1941,8 +1974,10 @@ class Employee(NamedTuple):
1941
1974
1942
1975
Employee = collections.namedtuple('Employee', ['name', 'id'])
1943
1976
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
1946
1981
are in the _fields attribute, which is part of the namedtuple
1947
1982
API.) Alternative equivalent keyword syntax is also accepted::
1948
1983
0 commit comments