95
95
'NamedTuple' , # Not really a type.
96
96
'TypedDict' , # Not really a type.
97
97
'Generator' ,
98
-
98
+
99
99
# Other concrete types.
100
100
'BinaryIO' ,
101
101
'IO' ,
@@ -134,7 +134,7 @@ def _type_convert(arg, module=None):
134
134
return arg
135
135
136
136
137
- def _type_check (arg , msg , is_argument = True , module = None ):
137
+ def _type_check (arg , msg , is_argument = True , module = None , * , is_class = False ):
138
138
"""Check that the argument is a type, and return it (internal helper).
139
139
140
140
As a special case, accept None and return type(None) instead. Also wrap strings
@@ -147,14 +147,16 @@ def _type_check(arg, msg, is_argument=True, module=None):
147
147
We append the repr() of the actual value (truncated to 100 chars).
148
148
"""
149
149
invalid_generic_forms = (Generic , Protocol )
150
- if is_argument :
151
- invalid_generic_forms = invalid_generic_forms + (ClassVar , Final )
150
+ if not is_class :
151
+ invalid_generic_forms += (ClassVar ,)
152
+ if is_argument :
153
+ invalid_generic_forms += (Final ,)
152
154
153
155
arg = _type_convert (arg , module = module )
154
156
if (isinstance (arg , _GenericAlias ) and
155
157
arg .__origin__ in invalid_generic_forms ):
156
158
raise TypeError (f"{ arg } is not valid as type argument" )
157
- if arg in (Any , NoReturn ):
159
+ if arg in (Any , NoReturn , Final ):
158
160
return arg
159
161
if isinstance (arg , _SpecialForm ) or arg in (Generic , Protocol ):
160
162
raise TypeError (f"Plain { arg } is not valid as type argument" )
@@ -517,9 +519,10 @@ class ForwardRef(_Final, _root=True):
517
519
518
520
__slots__ = ('__forward_arg__' , '__forward_code__' ,
519
521
'__forward_evaluated__' , '__forward_value__' ,
520
- '__forward_is_argument__' , '__forward_module__' )
522
+ '__forward_is_argument__' , '__forward_is_class__' ,
523
+ '__forward_module__' )
521
524
522
- def __init__ (self , arg , is_argument = True , module = None ):
525
+ def __init__ (self , arg , is_argument = True , module = None , * , is_class = False ):
523
526
if not isinstance (arg , str ):
524
527
raise TypeError (f"Forward reference must be a string -- got { arg !r} " )
525
528
try :
@@ -531,6 +534,7 @@ def __init__(self, arg, is_argument=True, module=None):
531
534
self .__forward_evaluated__ = False
532
535
self .__forward_value__ = None
533
536
self .__forward_is_argument__ = is_argument
537
+ self .__forward_is_class__ = is_class
534
538
self .__forward_module__ = module
535
539
536
540
def _evaluate (self , globalns , localns , recursive_guard ):
@@ -547,10 +551,11 @@ def _evaluate(self, globalns, localns, recursive_guard):
547
551
globalns = getattr (
548
552
sys .modules .get (self .__forward_module__ , None ), '__dict__' , globalns
549
553
)
550
- type_ = _type_check (
554
+ type_ = _type_check (
551
555
eval (self .__forward_code__ , globalns , localns ),
552
556
"Forward references must evaluate to types." ,
553
557
is_argument = self .__forward_is_argument__ ,
558
+ is_class = self .__forward_is_class__ ,
554
559
)
555
560
self .__forward_value__ = _eval_type (
556
561
type_ , globalns , localns , recursive_guard | {self .__forward_arg__ }
@@ -1450,7 +1455,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
1450
1455
if value is None :
1451
1456
value = type (None )
1452
1457
if isinstance (value , str ):
1453
- value = ForwardRef (value , is_argument = False )
1458
+ value = ForwardRef (value , is_argument = False , is_class = True )
1454
1459
value = _eval_type (value , base_globals , localns )
1455
1460
hints [name ] = value
1456
1461
return hints if include_extras else {k : _strip_annotations (t ) for k , t in hints .items ()}
@@ -1482,7 +1487,13 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
1482
1487
if value is None :
1483
1488
value = type (None )
1484
1489
if isinstance (value , str ):
1485
- value = ForwardRef (value )
1490
+ # class-level forward refs were handled above, this must be either
1491
+ # a module-level annotation or a function argument annotation
1492
+ value = ForwardRef (
1493
+ value ,
1494
+ is_argument = not isinstance (obj , types .ModuleType ),
1495
+ is_class = False ,
1496
+ )
1486
1497
value = _eval_type (value , globalns , localns )
1487
1498
if name in defaults and defaults [name ] is None :
1488
1499
value = Optional [value ]
0 commit comments