@@ -172,16 +172,16 @@ def __getattr__(self, attr):
172
172
_lazy_annotationlib = _LazyAnnotationLib ()
173
173
174
174
175
- def _type_convert (arg , module = None , * , allow_special_forms = False ):
175
+ def _type_convert (arg , module = None , * , allow_special_forms = False , owner = None ):
176
176
"""For converting None to type(None), and strings to ForwardRef."""
177
177
if arg is None :
178
178
return type (None )
179
179
if isinstance (arg , str ):
180
- return _make_forward_ref (arg , module = module , is_class = allow_special_forms )
180
+ return _make_forward_ref (arg , module = module , is_class = allow_special_forms , owner = owner )
181
181
return arg
182
182
183
183
184
- def _type_check (arg , msg , is_argument = True , module = None , * , allow_special_forms = False ):
184
+ def _type_check (arg , msg , is_argument = True , module = None , * , allow_special_forms = False , owner = None ):
185
185
"""Check that the argument is a type, and return it (internal helper).
186
186
187
187
As a special case, accept None and return type(None) instead. Also wrap strings
@@ -199,7 +199,7 @@ def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms=
199
199
if is_argument :
200
200
invalid_generic_forms += (Final ,)
201
201
202
- arg = _type_convert (arg , module = module , allow_special_forms = allow_special_forms )
202
+ arg = _type_convert (arg , module = module , allow_special_forms = allow_special_forms , owner = owner )
203
203
if (isinstance (arg , _GenericAlias ) and
204
204
arg .__origin__ in invalid_generic_forms ):
205
205
raise TypeError (f"{ arg } is not valid as type argument" )
@@ -431,7 +431,7 @@ def __repr__(self):
431
431
432
432
433
433
def _eval_type (t , globalns , localns , type_params = _sentinel , * , recursive_guard = frozenset (),
434
- format = None , owner = None , parent_fwdref = None ):
434
+ format = None , owner = None , parent_fwdref = None , prefer_fwd_module = False ):
435
435
"""Evaluate all forward references in the given type t.
436
436
437
437
For use of globalns and localns see the docstring for get_type_hints().
@@ -444,8 +444,20 @@ def _eval_type(t, globalns, localns, type_params=_sentinel, *, recursive_guard=f
444
444
if isinstance (t , _lazy_annotationlib .ForwardRef ):
445
445
# If the forward_ref has __forward_module__ set, evaluate() infers the globals
446
446
# from the module, and it will probably pick better than the globals we have here.
447
- if t .__forward_module__ is not None :
447
+ # We do this only for calls from get_type_hints() (which opts in through the
448
+ # prefer_fwd_module flag), so that the default behavior remains more straightforward.
449
+ if prefer_fwd_module and t .__forward_module__ is not None :
448
450
globalns = None
451
+ # If there are type params on the owner, we need to add them back, because
452
+ # annotationlib won't.
453
+ if owner_type_params := getattr (owner , "__type_params__" , None ):
454
+ globalns = getattr (
455
+ sys .modules .get (t .__forward_module__ , None ), "__dict__" , None
456
+ )
457
+ if globalns is not None :
458
+ globalns = dict (globalns )
459
+ for type_param in owner_type_params :
460
+ globalns [type_param .__name__ ] = type_param
449
461
return evaluate_forward_ref (t , globals = globalns , locals = localns ,
450
462
type_params = type_params , owner = owner ,
451
463
_recursive_guard = recursive_guard , format = format )
@@ -466,7 +478,7 @@ def _eval_type(t, globalns, localns, type_params=_sentinel, *, recursive_guard=f
466
478
ev_args = tuple (
467
479
_eval_type (
468
480
a , globalns , localns , type_params , recursive_guard = recursive_guard ,
469
- format = format , owner = owner ,
481
+ format = format , owner = owner , prefer_fwd_module = prefer_fwd_module ,
470
482
)
471
483
for a in t .__args__
472
484
)
@@ -2363,7 +2375,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False,
2363
2375
if isinstance (value , str ):
2364
2376
value = _make_forward_ref (value , is_argument = False , is_class = True )
2365
2377
value = _eval_type (value , base_globals , base_locals , (),
2366
- format = format , owner = obj )
2378
+ format = format , owner = obj , prefer_fwd_module = True )
2367
2379
if value is None :
2368
2380
value = type (None )
2369
2381
hints [name ] = value
@@ -2408,7 +2420,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False,
2408
2420
is_argument = not isinstance (obj , types .ModuleType ),
2409
2421
is_class = False ,
2410
2422
)
2411
- value = _eval_type (value , globalns , localns , (), format = format , owner = obj )
2423
+ value = _eval_type (value , globalns , localns , (), format = format , owner = obj , prefer_fwd_module = True )
2412
2424
if value is None :
2413
2425
value = type (None )
2414
2426
hints [name ] = value
@@ -3147,7 +3159,7 @@ def __new__(cls, name, bases, ns, total=True):
3147
3159
own_annotations = {}
3148
3160
msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
3149
3161
own_checked_annotations = {
3150
- n : _type_check (tp , msg , module = tp_dict .__module__ )
3162
+ n : _type_check (tp , msg , owner = tp_dict , module = tp_dict .__module__ )
3151
3163
for n , tp in own_annotations .items ()
3152
3164
}
3153
3165
required_keys = set ()
0 commit comments