|
|
@ -151,7 +151,7 @@ def _type_convert(arg, module=None): |
|
|
return arg |
|
|
return arg |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _type_check(arg, msg, is_argument=True, module=None): |
|
|
|
|
|
|
|
|
def _type_check(arg, msg, is_argument=True, module=None, *, is_class=False): |
|
|
"""Check that the argument is a type, and return it (internal helper). |
|
|
"""Check that the argument is a type, and return it (internal helper). |
|
|
|
|
|
|
|
|
As a special case, accept None and return type(None) instead. Also wrap strings |
|
|
As a special case, accept None and return type(None) instead. Also wrap strings |
|
|
@ -164,14 +164,16 @@ def _type_check(arg, msg, is_argument=True, module=None): |
|
|
We append the repr() of the actual value (truncated to 100 chars). |
|
|
We append the repr() of the actual value (truncated to 100 chars). |
|
|
""" |
|
|
""" |
|
|
invalid_generic_forms = (Generic, Protocol) |
|
|
invalid_generic_forms = (Generic, Protocol) |
|
|
if is_argument: |
|
|
|
|
|
invalid_generic_forms = invalid_generic_forms + (ClassVar, Final) |
|
|
|
|
|
|
|
|
if not is_class: |
|
|
|
|
|
invalid_generic_forms += (ClassVar,) |
|
|
|
|
|
if is_argument: |
|
|
|
|
|
invalid_generic_forms += (Final,) |
|
|
|
|
|
|
|
|
arg = _type_convert(arg, module=module) |
|
|
arg = _type_convert(arg, module=module) |
|
|
if (isinstance(arg, _GenericAlias) and |
|
|
if (isinstance(arg, _GenericAlias) and |
|
|
arg.__origin__ in invalid_generic_forms): |
|
|
arg.__origin__ in invalid_generic_forms): |
|
|
raise TypeError(f"{arg} is not valid as type argument") |
|
|
raise TypeError(f"{arg} is not valid as type argument") |
|
|
if arg in (Any, NoReturn): |
|
|
|
|
|
|
|
|
if arg in (Any, NoReturn, Final): |
|
|
return arg |
|
|
return arg |
|
|
if isinstance(arg, _SpecialForm) or arg in (Generic, Protocol): |
|
|
if isinstance(arg, _SpecialForm) or arg in (Generic, Protocol): |
|
|
raise TypeError(f"Plain {arg} is not valid as type argument") |
|
|
raise TypeError(f"Plain {arg} is not valid as type argument") |
|
|
@ -662,9 +664,10 @@ class ForwardRef(_Final, _root=True): |
|
|
|
|
|
|
|
|
__slots__ = ('__forward_arg__', '__forward_code__', |
|
|
__slots__ = ('__forward_arg__', '__forward_code__', |
|
|
'__forward_evaluated__', '__forward_value__', |
|
|
'__forward_evaluated__', '__forward_value__', |
|
|
'__forward_is_argument__', '__forward_module__') |
|
|
|
|
|
|
|
|
'__forward_is_argument__', '__forward_is_class__', |
|
|
|
|
|
'__forward_module__') |
|
|
|
|
|
|
|
|
def __init__(self, arg, is_argument=True, module=None): |
|
|
|
|
|
|
|
|
def __init__(self, arg, is_argument=True, module=None, *, is_class=False): |
|
|
if not isinstance(arg, str): |
|
|
if not isinstance(arg, str): |
|
|
raise TypeError(f"Forward reference must be a string -- got {arg!r}") |
|
|
raise TypeError(f"Forward reference must be a string -- got {arg!r}") |
|
|
try: |
|
|
try: |
|
|
@ -676,6 +679,7 @@ class ForwardRef(_Final, _root=True): |
|
|
self.__forward_evaluated__ = False |
|
|
self.__forward_evaluated__ = False |
|
|
self.__forward_value__ = None |
|
|
self.__forward_value__ = None |
|
|
self.__forward_is_argument__ = is_argument |
|
|
self.__forward_is_argument__ = is_argument |
|
|
|
|
|
self.__forward_is_class__ = is_class |
|
|
self.__forward_module__ = module |
|
|
self.__forward_module__ = module |
|
|
|
|
|
|
|
|
def _evaluate(self, globalns, localns, recursive_guard): |
|
|
def _evaluate(self, globalns, localns, recursive_guard): |
|
|
@ -692,10 +696,11 @@ class ForwardRef(_Final, _root=True): |
|
|
globalns = getattr( |
|
|
globalns = getattr( |
|
|
sys.modules.get(self.__forward_module__, None), '__dict__', globalns |
|
|
sys.modules.get(self.__forward_module__, None), '__dict__', globalns |
|
|
) |
|
|
) |
|
|
type_ =_type_check( |
|
|
|
|
|
|
|
|
type_ = _type_check( |
|
|
eval(self.__forward_code__, globalns, localns), |
|
|
eval(self.__forward_code__, globalns, localns), |
|
|
"Forward references must evaluate to types.", |
|
|
"Forward references must evaluate to types.", |
|
|
is_argument=self.__forward_is_argument__, |
|
|
is_argument=self.__forward_is_argument__, |
|
|
|
|
|
is_class=self.__forward_is_class__, |
|
|
) |
|
|
) |
|
|
self.__forward_value__ = _eval_type( |
|
|
self.__forward_value__ = _eval_type( |
|
|
type_, globalns, localns, recursive_guard | {self.__forward_arg__} |
|
|
type_, globalns, localns, recursive_guard | {self.__forward_arg__} |
|
|
@ -1799,7 +1804,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False): |
|
|
if value is None: |
|
|
if value is None: |
|
|
value = type(None) |
|
|
value = type(None) |
|
|
if isinstance(value, str): |
|
|
if isinstance(value, str): |
|
|
value = ForwardRef(value, is_argument=False) |
|
|
|
|
|
|
|
|
value = ForwardRef(value, is_argument=False, is_class=True) |
|
|
value = _eval_type(value, base_globals, base_locals) |
|
|
value = _eval_type(value, base_globals, base_locals) |
|
|
hints[name] = value |
|
|
hints[name] = value |
|
|
return hints if include_extras else {k: _strip_annotations(t) for k, t in hints.items()} |
|
|
return hints if include_extras else {k: _strip_annotations(t) for k, t in hints.items()} |
|
|
@ -1831,7 +1836,13 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False): |
|
|
if value is None: |
|
|
if value is None: |
|
|
value = type(None) |
|
|
value = type(None) |
|
|
if isinstance(value, str): |
|
|
if isinstance(value, str): |
|
|
value = ForwardRef(value) |
|
|
|
|
|
|
|
|
# class-level forward refs were handled above, this must be either |
|
|
|
|
|
# a module-level annotation or a function argument annotation |
|
|
|
|
|
value = ForwardRef( |
|
|
|
|
|
value, |
|
|
|
|
|
is_argument=not isinstance(obj, types.ModuleType), |
|
|
|
|
|
is_class=False, |
|
|
|
|
|
) |
|
|
value = _eval_type(value, globalns, localns) |
|
|
value = _eval_type(value, globalns, localns) |
|
|
if name in defaults and defaults[name] is None: |
|
|
if name in defaults and defaults[name] is None: |
|
|
value = Optional[value] |
|
|
value = Optional[value] |
|
|
|