9
9
import typing
10
10
import warnings
11
11
from functools import lru_cache , partial
12
- from typing import Any , Callable , Literal , overload
12
+ from typing import TYPE_CHECKING , Any , Callable
13
13
14
14
import typing_extensions
15
15
from typing_extensions import TypeIs , deprecated , get_args , get_origin
23
23
from types import EllipsisType as EllipsisType
24
24
from types import NoneType as NoneType
25
25
26
+ if TYPE_CHECKING :
27
+ from pydantic import BaseModel
26
28
27
29
# See https://typing-extensions.readthedocs.io/en/latest/#runtime-use-of-types:
28
30
@@ -467,34 +469,57 @@ def _type_convert(arg: Any) -> Any:
467
469
return arg
468
470
469
471
470
- @overload
471
- def get_cls_type_hints (
472
- obj : type [Any ],
473
- * ,
474
- ns_resolver : NsResolver | None = None ,
475
- lenient : Literal [True ],
476
- ) -> dict [str , tuple [Any , bool ]]: ...
477
- @overload
478
- def get_cls_type_hints (
479
- obj : type [Any ],
472
+ def get_model_type_hints (
473
+ obj : type [BaseModel ],
480
474
* ,
481
475
ns_resolver : NsResolver | None = None ,
482
- lenient : Literal [False ] = ...,
483
- ) -> dict [str , Any ]: ...
476
+ ) -> dict [str , tuple [Any , bool ]]:
477
+ """Collect annotations from a Pydantic model class, including those from parent classes.
478
+
479
+ Args:
480
+ obj: The Pydantic model to inspect.
481
+ ns_resolver: A namespace resolver instance to use. Defaults to an empty instance.
482
+
483
+ Returns:
484
+ A dictionary mapping annotation names to a two-tuple: the first element is the evaluated
485
+ type or the original annotation if a `NameError` occurred, the second element is a boolean
486
+ indicating if whether the evaluation succeeded.
487
+ """
488
+ hints : dict [str , Any ] | dict [str , tuple [Any , bool ]] = {}
489
+ ns_resolver = ns_resolver or NsResolver ()
490
+
491
+ for base in reversed (obj .__mro__ ):
492
+ ann : dict [str , Any ] | None = base .__dict__ .get ('__annotations__' )
493
+ if not ann or isinstance (ann , types .GetSetDescriptorType ):
494
+ continue
495
+ with ns_resolver .push (base ):
496
+ globalns , localns = ns_resolver .types_namespace
497
+ for name , value in ann .items ():
498
+ if name .startswith ('_' ):
499
+ # For private attributes, we only need the annotation to detect the `ClassVar` special form.
500
+ # For this reason, we still try to evaluate it, but we also catch any possible exception (on
501
+ # top of the `NameError`s caught in `try_eval_type`) that could happen so that users are free
502
+ # to use any kind of forward annotation for private fields (e.g. circular imports, new typing
503
+ # syntax, etc).
504
+ try :
505
+ hints [name ] = try_eval_type (value , globalns , localns )
506
+ except Exception :
507
+ hints [name ] = (value , False )
508
+ else :
509
+ hints [name ] = try_eval_type (value , globalns , localns )
510
+ return hints
511
+
512
+
484
513
def get_cls_type_hints (
485
514
obj : type [Any ],
486
515
* ,
487
516
ns_resolver : NsResolver | None = None ,
488
- lenient : bool = False ,
489
- ) -> dict [str , Any ] | dict [str , tuple [Any , bool ]]:
517
+ ) -> dict [str , Any ]:
490
518
"""Collect annotations from a class, including those from parent classes.
491
519
492
520
Args:
493
521
obj: The class to inspect.
494
522
ns_resolver: A namespace resolver instance to use. Defaults to an empty instance.
495
- lenient: Whether to keep unresolvable annotations as is or re-raise the `NameError` exception.
496
- If lenient, an extra boolean flag is set for each annotation value to indicate whether the
497
- evaluation succeeded or not. Default: re-raise.
498
523
"""
499
524
hints : dict [str , Any ] | dict [str , tuple [Any , bool ]] = {}
500
525
ns_resolver = ns_resolver or NsResolver ()
@@ -506,10 +531,7 @@ def get_cls_type_hints(
506
531
with ns_resolver .push (base ):
507
532
globalns , localns = ns_resolver .types_namespace
508
533
for name , value in ann .items ():
509
- if lenient :
510
- hints [name ] = try_eval_type (value , globalns , localns )
511
- else :
512
- hints [name ] = eval_type (value , globalns , localns )
534
+ hints [name ] = eval_type (value , globalns , localns )
513
535
return hints
514
536
515
537
0 commit comments