1"""Logic for interacting with type annotations, mostly extensions, shims and hacks to wrap Python's typing module."""
2
3from __future__ import annotations
4
5import collections.abc
6import re
7import sys
8import types
9import typing
10from functools import partial
11from typing import TYPE_CHECKING, Any, Callable, cast
12
13import typing_extensions
14from typing_extensions import deprecated, get_args, get_origin
15from typing_inspection import typing_objects
16from typing_inspection.introspection import is_union_origin
17
18from pydantic.version import version_short
19
20from ._namespace_utils import GlobalsNamespace, MappingNamespace, NsResolver, get_module_ns_of
21
22if sys.version_info < (3, 10):
23 NoneType = type(None)
24 EllipsisType = type(Ellipsis)
25else:
26 from types import EllipsisType as EllipsisType
27 from types import NoneType as NoneType
28
29if TYPE_CHECKING:
30 from pydantic import BaseModel
31
32# As per https://typing-extensions.readthedocs.io/en/latest/#runtime-use-of-types,
33# always check for both `typing` and `typing_extensions` variants of a typing construct.
34# (this is implemented differently than the suggested approach in the `typing_extensions`
35# docs for performance).
36
37
38_t_annotated = typing.Annotated
39_te_annotated = typing_extensions.Annotated
40
41
42def is_annotated(tp: Any, /) -> bool:
43 """Return whether the provided argument is a `Annotated` special form.
44
45 ```python {test="skip" lint="skip"}
46 is_annotated(Annotated[int, ...])
47 #> True
48 ```
49 """
50 origin = get_origin(tp)
51 return origin is _t_annotated or origin is _te_annotated
52
53
54def annotated_type(tp: Any, /) -> Any | None:
55 """Return the type of the `Annotated` special form, or `None`."""
56 return tp.__origin__ if typing_objects.is_annotated(get_origin(tp)) else None
57
58
59def unpack_type(tp: Any, /) -> Any | None:
60 """Return the type wrapped by the `Unpack` special form, or `None`."""
61 return get_args(tp)[0] if typing_objects.is_unpack(get_origin(tp)) else None
62
63
64def is_hashable(tp: Any, /) -> bool:
65 """Return whether the provided argument is the `Hashable` class.
66
67 ```python {test="skip" lint="skip"}
68 is_hashable(Hashable)
69 #> True
70 ```
71 """
72 # `get_origin` is documented as normalizing any typing-module aliases to `collections` classes,
73 # hence the second check:
74 return tp is collections.abc.Hashable or get_origin(tp) is collections.abc.Hashable
75
76
77def is_callable(tp: Any, /) -> bool:
78 """Return whether the provided argument is a `Callable`, parametrized or not.
79
80 ```python {test="skip" lint="skip"}
81 is_callable(Callable[[int], str])
82 #> True
83 is_callable(typing.Callable)
84 #> True
85 is_callable(collections.abc.Callable)
86 #> True
87 ```
88 """
89 # `get_origin` is documented as normalizing any typing-module aliases to `collections` classes,
90 # hence the second check:
91 return tp is collections.abc.Callable or get_origin(tp) is collections.abc.Callable
92
93
94_classvar_re = re.compile(r'((\w+\.)?Annotated\[)?(\w+\.)?ClassVar\[')
95
96
97def is_classvar_annotation(tp: Any, /) -> bool:
98 """Return whether the provided argument represents a class variable annotation.
99
100 Although not explicitly stated by the typing specification, `ClassVar` can be used
101 inside `Annotated` and as such, this function checks for this specific scenario.
102
103 Because this function is used to detect class variables before evaluating forward references
104 (or because evaluation failed), we also implement a naive regex match implementation. This is
105 required because class variables are inspected before fields are collected, so we try to be
106 as accurate as possible.
107 """
108 if typing_objects.is_classvar(tp):
109 return True
110
111 origin = get_origin(tp)
112
113 if typing_objects.is_classvar(origin):
114 return True
115
116 if typing_objects.is_annotated(origin):
117 annotated_type = tp.__origin__
118 if typing_objects.is_classvar(annotated_type) or typing_objects.is_classvar(get_origin(annotated_type)):
119 return True
120
121 str_ann: str | None = None
122 if isinstance(tp, typing.ForwardRef):
123 str_ann = tp.__forward_arg__
124 if isinstance(tp, str):
125 str_ann = tp
126
127 if str_ann is not None and _classvar_re.match(str_ann):
128 # stdlib dataclasses do something similar, although a bit more advanced
129 # (see `dataclass._is_type`).
130 return True
131
132 return False
133
134
135_t_final = typing.Final
136_te_final = typing_extensions.Final
137
138
139# TODO implement `is_finalvar_annotation` as Final can be wrapped with other special forms:
140def is_finalvar(tp: Any, /) -> bool:
141 """Return whether the provided argument is a `Final` special form, parametrized or not.
142
143 ```python {test="skip" lint="skip"}
144 is_finalvar(Final[int])
145 #> True
146 is_finalvar(Final)
147 #> True
148 """
149 # Final is not necessarily parametrized:
150 if tp is _t_final or tp is _te_final:
151 return True
152 origin = get_origin(tp)
153 return origin is _t_final or origin is _te_final
154
155
156_NONE_TYPES: tuple[Any, ...] = (None, NoneType, typing.Literal[None], typing_extensions.Literal[None])
157
158
159def is_none_type(tp: Any, /) -> bool:
160 """Return whether the argument represents the `None` type as part of an annotation.
161
162 ```python {test="skip" lint="skip"}
163 is_none_type(None)
164 #> True
165 is_none_type(NoneType)
166 #> True
167 is_none_type(Literal[None])
168 #> True
169 is_none_type(type[None])
170 #> False
171 """
172 return tp in _NONE_TYPES
173
174
175def is_namedtuple(tp: Any, /) -> bool:
176 """Return whether the provided argument is a named tuple class.
177
178 The class can be created using `typing.NamedTuple` or `collections.namedtuple`.
179 Parametrized generic classes are *not* assumed to be named tuples.
180 """
181 from ._utils import lenient_issubclass # circ. import
182
183 return lenient_issubclass(tp, tuple) and hasattr(tp, '_fields')
184
185
186# TODO In 2.12, delete this export. It is currently defined only to not break
187# pydantic-settings which relies on it:
188origin_is_union = is_union_origin
189
190
191def is_generic_alias(tp: Any, /) -> bool:
192 return isinstance(tp, (types.GenericAlias, typing._GenericAlias)) # pyright: ignore[reportAttributeAccessIssue]
193
194
195# TODO: Ideally, we should avoid relying on the private `typing` constructs:
196
197if sys.version_info < (3, 10):
198 WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias) # pyright: ignore[reportAttributeAccessIssue]
199else:
200 WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias, types.UnionType) # pyright: ignore[reportAttributeAccessIssue]
201
202
203# Similarly, we shouldn't rely on this `_Final` class, which is even more private than `_GenericAlias`:
204typing_base: Any = typing._Final # pyright: ignore[reportAttributeAccessIssue]
205
206
207### Annotation evaluations functions:
208
209
210def parent_frame_namespace(*, parent_depth: int = 2, force: bool = False) -> dict[str, Any] | None:
211 """Fetch the local namespace of the parent frame where this function is called.
212
213 Using this function is mostly useful to resolve forward annotations pointing to members defined in a local namespace,
214 such as assignments inside a function. Using the standard library tools, it is currently not possible to resolve
215 such annotations:
216
217 ```python {lint="skip" test="skip"}
218 from typing import get_type_hints
219
220 def func() -> None:
221 Alias = int
222
223 class C:
224 a: 'Alias'
225
226 # Raises a `NameError: 'Alias' is not defined`
227 get_type_hints(C)
228 ```
229
230 Pydantic uses this function when a Pydantic model is being defined to fetch the parent frame locals. However,
231 this only allows us to fetch the parent frame namespace and not other parents (e.g. a model defined in a function,
232 itself defined in another function). Inspecting the next outer frames (using `f_back`) is not reliable enough
233 (see https://discuss.python.org/t/20659).
234
235 Because this function is mostly used to better resolve forward annotations, nothing is returned if the parent frame's
236 code object is defined at the module level. In this case, the locals of the frame will be the same as the module
237 globals where the class is defined (see `_namespace_utils.get_module_ns_of`). However, if you still want to fetch
238 the module globals (e.g. when rebuilding a model, where the frame where the rebuild call is performed might contain
239 members that you want to use for forward annotations evaluation), you can use the `force` parameter.
240
241 Args:
242 parent_depth: The depth at which to get the frame. Defaults to 2, meaning the parent frame where this function
243 is called will be used.
244 force: Whether to always return the frame locals, even if the frame's code object is defined at the module level.
245
246 Returns:
247 The locals of the namespace, or `None` if it was skipped as per the described logic.
248 """
249 frame = sys._getframe(parent_depth)
250
251 if frame.f_code.co_name.startswith('<generic parameters of'):
252 # As `parent_frame_namespace` is mostly called in `ModelMetaclass.__new__`,
253 # the parent frame can be the annotation scope if the PEP 695 generic syntax is used.
254 # (see https://docs.python.org/3/reference/executionmodel.html#annotation-scopes,
255 # https://docs.python.org/3/reference/compound_stmts.html#generic-classes).
256 # In this case, the code name is set to `<generic parameters of MyClass>`,
257 # and we need to skip this frame as it is irrelevant.
258 frame = cast(types.FrameType, frame.f_back) # guaranteed to not be `None`
259
260 # note, we don't copy frame.f_locals here (or during the last return call), because we don't expect the namespace to be
261 # modified down the line if this becomes a problem, we could implement some sort of frozen mapping structure to enforce this.
262 if force:
263 return frame.f_locals
264
265 # If either of the following conditions are true, the class is defined at the top module level.
266 # To better understand why we need both of these checks, see
267 # https://github.com/pydantic/pydantic/pull/10113#discussion_r1714981531.
268 if frame.f_back is None or frame.f_code.co_name == '<module>':
269 return None
270
271 return frame.f_locals
272
273
274def _type_convert(arg: Any) -> Any:
275 """Convert `None` to `NoneType` and strings to `ForwardRef` instances.
276
277 This is a backport of the private `typing._type_convert` function. When
278 evaluating a type, `ForwardRef._evaluate` ends up being called, and is
279 responsible for making this conversion. However, we still have to apply
280 it for the first argument passed to our type evaluation functions, similarly
281 to the `typing.get_type_hints` function.
282 """
283 if arg is None:
284 return NoneType
285 if isinstance(arg, str):
286 # Like `typing.get_type_hints`, assume the arg can be in any context,
287 # hence the proper `is_argument` and `is_class` args:
288 return _make_forward_ref(arg, is_argument=False, is_class=True)
289 return arg
290
291
292def get_model_type_hints(
293 obj: type[BaseModel],
294 *,
295 ns_resolver: NsResolver | None = None,
296) -> dict[str, tuple[Any, bool]]:
297 """Collect annotations from a Pydantic model class, including those from parent classes.
298
299 Args:
300 obj: The Pydantic model to inspect.
301 ns_resolver: A namespace resolver instance to use. Defaults to an empty instance.
302
303 Returns:
304 A dictionary mapping annotation names to a two-tuple: the first element is the evaluated
305 type or the original annotation if a `NameError` occurred, the second element is a boolean
306 indicating if whether the evaluation succeeded.
307 """
308 hints: dict[str, Any] | dict[str, tuple[Any, bool]] = {}
309 ns_resolver = ns_resolver or NsResolver()
310
311 for base in reversed(obj.__mro__):
312 ann: dict[str, Any] | None = base.__dict__.get('__annotations__')
313 if not ann or isinstance(ann, types.GetSetDescriptorType):
314 continue
315 with ns_resolver.push(base):
316 globalns, localns = ns_resolver.types_namespace
317 for name, value in ann.items():
318 if name.startswith('_'):
319 # For private attributes, we only need the annotation to detect the `ClassVar` special form.
320 # For this reason, we still try to evaluate it, but we also catch any possible exception (on
321 # top of the `NameError`s caught in `try_eval_type`) that could happen so that users are free
322 # to use any kind of forward annotation for private fields (e.g. circular imports, new typing
323 # syntax, etc).
324 try:
325 hints[name] = try_eval_type(value, globalns, localns)
326 except Exception:
327 hints[name] = (value, False)
328 else:
329 hints[name] = try_eval_type(value, globalns, localns)
330 return hints
331
332
333def get_cls_type_hints(
334 obj: type[Any],
335 *,
336 ns_resolver: NsResolver | None = None,
337) -> dict[str, Any]:
338 """Collect annotations from a class, including those from parent classes.
339
340 Args:
341 obj: The class to inspect.
342 ns_resolver: A namespace resolver instance to use. Defaults to an empty instance.
343 """
344 hints: dict[str, Any] | dict[str, tuple[Any, bool]] = {}
345 ns_resolver = ns_resolver or NsResolver()
346
347 for base in reversed(obj.__mro__):
348 ann: dict[str, Any] | None = base.__dict__.get('__annotations__')
349 if not ann or isinstance(ann, types.GetSetDescriptorType):
350 continue
351 with ns_resolver.push(base):
352 globalns, localns = ns_resolver.types_namespace
353 for name, value in ann.items():
354 hints[name] = eval_type(value, globalns, localns)
355 return hints
356
357
358def try_eval_type(
359 value: Any,
360 globalns: GlobalsNamespace | None = None,
361 localns: MappingNamespace | None = None,
362) -> tuple[Any, bool]:
363 """Try evaluating the annotation using the provided namespaces.
364
365 Args:
366 value: The value to evaluate. If `None`, it will be replaced by `type[None]`. If an instance
367 of `str`, it will be converted to a `ForwardRef`.
368 localns: The global namespace to use during annotation evaluation.
369 globalns: The local namespace to use during annotation evaluation.
370
371 Returns:
372 A two-tuple containing the possibly evaluated type and a boolean indicating
373 whether the evaluation succeeded or not.
374 """
375 value = _type_convert(value)
376
377 try:
378 return eval_type_backport(value, globalns, localns), True
379 except NameError:
380 return value, False
381
382
383def eval_type(
384 value: Any,
385 globalns: GlobalsNamespace | None = None,
386 localns: MappingNamespace | None = None,
387) -> Any:
388 """Evaluate the annotation using the provided namespaces.
389
390 Args:
391 value: The value to evaluate. If `None`, it will be replaced by `type[None]`. If an instance
392 of `str`, it will be converted to a `ForwardRef`.
393 localns: The global namespace to use during annotation evaluation.
394 globalns: The local namespace to use during annotation evaluation.
395 """
396 value = _type_convert(value)
397 return eval_type_backport(value, globalns, localns)
398
399
400@deprecated(
401 '`eval_type_lenient` is deprecated, use `try_eval_type` instead.',
402 category=None,
403)
404def eval_type_lenient(
405 value: Any,
406 globalns: GlobalsNamespace | None = None,
407 localns: MappingNamespace | None = None,
408) -> Any:
409 ev, _ = try_eval_type(value, globalns, localns)
410 return ev
411
412
413def eval_type_backport(
414 value: Any,
415 globalns: GlobalsNamespace | None = None,
416 localns: MappingNamespace | None = None,
417 type_params: tuple[Any, ...] | None = None,
418) -> Any:
419 """An enhanced version of `typing._eval_type` which will fall back to using the `eval_type_backport`
420 package if it's installed to let older Python versions use newer typing constructs.
421
422 Specifically, this transforms `X | Y` into `typing.Union[X, Y]` and `list[X]` into `typing.List[X]`
423 (as well as all the types made generic in PEP 585) if the original syntax is not supported in the
424 current Python version.
425
426 This function will also display a helpful error if the value passed fails to evaluate.
427 """
428 try:
429 return _eval_type_backport(value, globalns, localns, type_params)
430 except TypeError as e:
431 if 'Unable to evaluate type annotation' in str(e):
432 raise
433
434 # If it is a `TypeError` and value isn't a `ForwardRef`, it would have failed during annotation definition.
435 # Thus we assert here for type checking purposes:
436 assert isinstance(value, typing.ForwardRef)
437
438 message = f'Unable to evaluate type annotation {value.__forward_arg__!r}.'
439 if sys.version_info >= (3, 11):
440 e.add_note(message)
441 raise
442 else:
443 raise TypeError(message) from e
444 except RecursionError as e:
445 # TODO ideally recursion errors should be checked in `eval_type` above, but `eval_type_backport`
446 # is used directly in some places.
447 message = (
448 "If you made use of an implicit recursive type alias (e.g. `MyType = list['MyType']), "
449 'consider using PEP 695 type aliases instead. For more details, refer to the documentation: '
450 f'https://docs.pydantic.dev/{version_short()}/concepts/types/#named-recursive-types'
451 )
452 if sys.version_info >= (3, 11):
453 e.add_note(message)
454 raise
455 else:
456 raise RecursionError(f'{e.args[0]}\n{message}')
457
458
459def _eval_type_backport(
460 value: Any,
461 globalns: GlobalsNamespace | None = None,
462 localns: MappingNamespace | None = None,
463 type_params: tuple[Any, ...] | None = None,
464) -> Any:
465 try:
466 return _eval_type(value, globalns, localns, type_params)
467 except TypeError as e:
468 if not (isinstance(value, typing.ForwardRef) and is_backport_fixable_error(e)):
469 raise
470
471 try:
472 from eval_type_backport import eval_type_backport
473 except ImportError:
474 raise TypeError(
475 f'Unable to evaluate type annotation {value.__forward_arg__!r}. If you are making use '
476 'of the new typing syntax (unions using `|` since Python 3.10 or builtins subscripting '
477 'since Python 3.9), you should either replace the use of new syntax with the existing '
478 '`typing` constructs or install the `eval_type_backport` package.'
479 ) from e
480
481 return eval_type_backport(
482 value,
483 globalns,
484 localns, # pyright: ignore[reportArgumentType], waiting on a new `eval_type_backport` release.
485 try_default=False,
486 )
487
488
489def _eval_type(
490 value: Any,
491 globalns: GlobalsNamespace | None = None,
492 localns: MappingNamespace | None = None,
493 type_params: tuple[Any, ...] | None = None,
494) -> Any:
495 if sys.version_info >= (3, 13):
496 return typing._eval_type( # type: ignore
497 value, globalns, localns, type_params=type_params
498 )
499 else:
500 return typing._eval_type( # type: ignore
501 value, globalns, localns
502 )
503
504
505def is_backport_fixable_error(e: TypeError) -> bool:
506 msg = str(e)
507
508 return sys.version_info < (3, 10) and msg.startswith('unsupported operand type(s) for |: ')
509
510
511def get_function_type_hints(
512 function: Callable[..., Any],
513 *,
514 include_keys: set[str] | None = None,
515 globalns: GlobalsNamespace | None = None,
516 localns: MappingNamespace | None = None,
517) -> dict[str, Any]:
518 """Return type hints for a function.
519
520 This is similar to the `typing.get_type_hints` function, with a few differences:
521 - Support `functools.partial` by using the underlying `func` attribute.
522 - Do not wrap type annotation of a parameter with `Optional` if it has a default value of `None`
523 (related bug: https://github.com/python/cpython/issues/90353, only fixed in 3.11+).
524 """
525 try:
526 if isinstance(function, partial):
527 annotations = function.func.__annotations__
528 else:
529 annotations = function.__annotations__
530 except AttributeError:
531 # Some functions (e.g. builtins) don't have annotations:
532 return {}
533
534 if globalns is None:
535 globalns = get_module_ns_of(function)
536 type_params: tuple[Any, ...] | None = None
537 if localns is None:
538 # If localns was specified, it is assumed to already contain type params. This is because
539 # Pydantic has more advanced logic to do so (see `_namespace_utils.ns_for_function`).
540 type_params = getattr(function, '__type_params__', ())
541
542 type_hints = {}
543 for name, value in annotations.items():
544 if include_keys is not None and name not in include_keys:
545 continue
546 if value is None:
547 value = NoneType
548 elif isinstance(value, str):
549 value = _make_forward_ref(value)
550
551 type_hints[name] = eval_type_backport(value, globalns, localns, type_params)
552
553 return type_hints
554
555
556if sys.version_info < (3, 9, 8) or (3, 10) <= sys.version_info < (3, 10, 1):
557
558 def _make_forward_ref(
559 arg: Any,
560 is_argument: bool = True,
561 *,
562 is_class: bool = False,
563 ) -> typing.ForwardRef:
564 """Wrapper for ForwardRef that accounts for the `is_class` argument missing in older versions.
565 The `module` argument is omitted as it breaks <3.9.8, =3.10.0 and isn't used in the calls below.
566
567 See https://github.com/python/cpython/pull/28560 for some background.
568 The backport happened on 3.9.8, see:
569 https://github.com/pydantic/pydantic/discussions/6244#discussioncomment-6275458,
570 and on 3.10.1 for the 3.10 branch, see:
571 https://github.com/pydantic/pydantic/issues/6912
572
573 Implemented as EAFP with memory.
574 """
575 return typing.ForwardRef(arg, is_argument)
576
577else:
578 _make_forward_ref = typing.ForwardRef
579
580
581if sys.version_info >= (3, 10):
582 get_type_hints = typing.get_type_hints
583
584else:
585 """
586 For older versions of python, we have a custom implementation of `get_type_hints` which is a close as possible to
587 the implementation in CPython 3.10.8.
588 """
589
590 @typing.no_type_check
591 def get_type_hints( # noqa: C901
592 obj: Any,
593 globalns: dict[str, Any] | None = None,
594 localns: dict[str, Any] | None = None,
595 include_extras: bool = False,
596 ) -> dict[str, Any]: # pragma: no cover
597 """Taken verbatim from python 3.10.8 unchanged, except:
598 * type annotations of the function definition above.
599 * prefixing `typing.` where appropriate
600 * Use `_make_forward_ref` instead of `typing.ForwardRef` to handle the `is_class` argument.
601
602 https://github.com/python/cpython/blob/aaaf5174241496afca7ce4d4584570190ff972fe/Lib/typing.py#L1773-L1875
603
604 DO NOT CHANGE THIS METHOD UNLESS ABSOLUTELY NECESSARY.
605 ======================================================
606
607 Return type hints for an object.
608
609 This is often the same as obj.__annotations__, but it handles
610 forward references encoded as string literals, adds Optional[t] if a
611 default value equal to None is set and recursively replaces all
612 'Annotated[T, ...]' with 'T' (unless 'include_extras=True').
613
614 The argument may be a module, class, method, or function. The annotations
615 are returned as a dictionary. For classes, annotations include also
616 inherited members.
617
618 TypeError is raised if the argument is not of a type that can contain
619 annotations, and an empty dictionary is returned if no annotations are
620 present.
621
622 BEWARE -- the behavior of globalns and localns is counterintuitive
623 (unless you are familiar with how eval() and exec() work). The
624 search order is locals first, then globals.
625
626 - If no dict arguments are passed, an attempt is made to use the
627 globals from obj (or the respective module's globals for classes),
628 and these are also used as the locals. If the object does not appear
629 to have globals, an empty dictionary is used. For classes, the search
630 order is globals first then locals.
631
632 - If one dict argument is passed, it is used for both globals and
633 locals.
634
635 - If two dict arguments are passed, they specify globals and
636 locals, respectively.
637 """
638 if getattr(obj, '__no_type_check__', None):
639 return {}
640 # Classes require a special treatment.
641 if isinstance(obj, type):
642 hints = {}
643 for base in reversed(obj.__mro__):
644 if globalns is None:
645 base_globals = getattr(sys.modules.get(base.__module__, None), '__dict__', {})
646 else:
647 base_globals = globalns
648 ann = base.__dict__.get('__annotations__', {})
649 if isinstance(ann, types.GetSetDescriptorType):
650 ann = {}
651 base_locals = dict(vars(base)) if localns is None else localns
652 if localns is None and globalns is None:
653 # This is surprising, but required. Before Python 3.10,
654 # get_type_hints only evaluated the globalns of
655 # a class. To maintain backwards compatibility, we reverse
656 # the globalns and localns order so that eval() looks into
657 # *base_globals* first rather than *base_locals*.
658 # This only affects ForwardRefs.
659 base_globals, base_locals = base_locals, base_globals
660 for name, value in ann.items():
661 if value is None:
662 value = type(None)
663 if isinstance(value, str):
664 value = _make_forward_ref(value, is_argument=False, is_class=True)
665
666 value = eval_type_backport(value, base_globals, base_locals)
667 hints[name] = value
668 if not include_extras and hasattr(typing, '_strip_annotations'):
669 return {
670 k: typing._strip_annotations(t) # type: ignore
671 for k, t in hints.items()
672 }
673 else:
674 return hints
675
676 if globalns is None:
677 if isinstance(obj, types.ModuleType):
678 globalns = obj.__dict__
679 else:
680 nsobj = obj
681 # Find globalns for the unwrapped object.
682 while hasattr(nsobj, '__wrapped__'):
683 nsobj = nsobj.__wrapped__
684 globalns = getattr(nsobj, '__globals__', {})
685 if localns is None:
686 localns = globalns
687 elif localns is None:
688 localns = globalns
689 hints = getattr(obj, '__annotations__', None)
690 if hints is None:
691 # Return empty annotations for something that _could_ have them.
692 if isinstance(obj, typing._allowed_types): # type: ignore
693 return {}
694 else:
695 raise TypeError(f'{obj!r} is not a module, class, method, or function.')
696 defaults = typing._get_defaults(obj) # type: ignore
697 hints = dict(hints)
698 for name, value in hints.items():
699 if value is None:
700 value = type(None)
701 if isinstance(value, str):
702 # class-level forward refs were handled above, this must be either
703 # a module-level annotation or a function argument annotation
704
705 value = _make_forward_ref(
706 value,
707 is_argument=not isinstance(obj, types.ModuleType),
708 is_class=False,
709 )
710 value = eval_type_backport(value, globalns, localns)
711 if name in defaults and defaults[name] is None:
712 value = typing.Optional[value]
713 hints[name] = value
714 return hints if include_extras else {k: typing._strip_annotations(t) for k, t in hints.items()} # type: ignore