您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

530 行
16 KiB

  1. import sys
  2. from os import PathLike
  3. from typing import ( # type: ignore
  4. TYPE_CHECKING,
  5. AbstractSet,
  6. Any,
  7. ClassVar,
  8. Dict,
  9. Generator,
  10. Iterable,
  11. List,
  12. Mapping,
  13. NewType,
  14. Optional,
  15. Sequence,
  16. Set,
  17. Tuple,
  18. Type,
  19. Union,
  20. _eval_type,
  21. cast,
  22. get_type_hints,
  23. )
  24. from typing_extensions import Annotated, Literal
  25. try:
  26. from typing import _TypingBase as typing_base # type: ignore
  27. except ImportError:
  28. from typing import _Final as typing_base # type: ignore
  29. try:
  30. from typing import GenericAlias as TypingGenericAlias # type: ignore
  31. except ImportError:
  32. # python < 3.9 does not have GenericAlias (list[int], tuple[str, ...] and so on)
  33. TypingGenericAlias = ()
  34. if sys.version_info < (3, 7):
  35. if TYPE_CHECKING:
  36. class ForwardRef:
  37. def __init__(self, arg: Any):
  38. pass
  39. def _eval_type(self, globalns: Any, localns: Any) -> Any:
  40. pass
  41. else:
  42. from typing import _ForwardRef as ForwardRef
  43. else:
  44. from typing import ForwardRef
  45. if sys.version_info < (3, 7):
  46. def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
  47. return type_._eval_type(globalns, localns)
  48. elif sys.version_info < (3, 9):
  49. def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
  50. return type_._evaluate(globalns, localns)
  51. else:
  52. def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any:
  53. # Even though it is the right signature for python 3.9, mypy complains with
  54. # `error: Too many arguments for "_evaluate" of "ForwardRef"` hence the cast...
  55. return cast(Any, type_)._evaluate(globalns, localns, set())
  56. if sys.version_info < (3, 9):
  57. # Ensure we always get all the whole `Annotated` hint, not just the annotated type.
  58. # For 3.6 to 3.8, `get_type_hints` doesn't recognize `typing_extensions.Annotated`,
  59. # so it already returns the full annotation
  60. get_all_type_hints = get_type_hints
  61. else:
  62. def get_all_type_hints(obj: Any, globalns: Any = None, localns: Any = None) -> Any:
  63. return get_type_hints(obj, globalns, localns, include_extras=True)
  64. if sys.version_info < (3, 7):
  65. from typing import Callable as Callable
  66. AnyCallable = Callable[..., Any]
  67. NoArgAnyCallable = Callable[[], Any]
  68. else:
  69. from collections.abc import Callable as Callable
  70. from typing import Callable as TypingCallable
  71. AnyCallable = TypingCallable[..., Any]
  72. NoArgAnyCallable = TypingCallable[[], Any]
  73. # Annotated[...] is implemented by returning an instance of one of these classes, depending on
  74. # python/typing_extensions version.
  75. AnnotatedTypeNames = {'AnnotatedMeta', '_AnnotatedAlias'}
  76. if sys.version_info < (3, 8):
  77. def get_origin(t: Type[Any]) -> Optional[Type[Any]]:
  78. if type(t).__name__ in AnnotatedTypeNames:
  79. return cast(Type[Any], Annotated) # mypy complains about _SpecialForm in py3.6
  80. return getattr(t, '__origin__', None)
  81. else:
  82. from typing import get_origin as _typing_get_origin
  83. def get_origin(tp: Type[Any]) -> Optional[Type[Any]]:
  84. """
  85. We can't directly use `typing.get_origin` since we need a fallback to support
  86. custom generic classes like `ConstrainedList`
  87. It should be useless once https://github.com/cython/cython/issues/3537 is
  88. solved and https://github.com/samuelcolvin/pydantic/pull/1753 is merged.
  89. """
  90. if type(tp).__name__ in AnnotatedTypeNames:
  91. return cast(Type[Any], Annotated) # mypy complains about _SpecialForm
  92. return _typing_get_origin(tp) or getattr(tp, '__origin__', None)
  93. if sys.version_info < (3, 7): # noqa: C901 (ignore complexity)
  94. def get_args(t: Type[Any]) -> Tuple[Any, ...]:
  95. """Simplest get_args compatibility layer possible.
  96. The Python 3.6 typing module does not have `_GenericAlias` so
  97. this won't work for everything. In particular this will not
  98. support the `generics` module (we don't support generic models in
  99. python 3.6).
  100. """
  101. if type(t).__name__ in AnnotatedTypeNames:
  102. return t.__args__ + t.__metadata__
  103. return getattr(t, '__args__', ())
  104. elif sys.version_info < (3, 8): # noqa: C901
  105. from typing import _GenericAlias
  106. def get_args(t: Type[Any]) -> Tuple[Any, ...]:
  107. """Compatibility version of get_args for python 3.7.
  108. Mostly compatible with the python 3.8 `typing` module version
  109. and able to handle almost all use cases.
  110. """
  111. if type(t).__name__ in AnnotatedTypeNames:
  112. return t.__args__ + t.__metadata__
  113. if isinstance(t, _GenericAlias):
  114. res = t.__args__
  115. if t.__origin__ is Callable and res and res[0] is not Ellipsis:
  116. res = (list(res[:-1]), res[-1])
  117. return res
  118. return getattr(t, '__args__', ())
  119. else:
  120. from typing import get_args as _typing_get_args
  121. def _generic_get_args(tp: Type[Any]) -> Tuple[Any, ...]:
  122. """
  123. In python 3.9, `typing.Dict`, `typing.List`, ...
  124. do have an empty `__args__` by default (instead of the generic ~T for example).
  125. In order to still support `Dict` for example and consider it as `Dict[Any, Any]`,
  126. we retrieve the `_nparams` value that tells us how many parameters it needs.
  127. """
  128. if hasattr(tp, '_nparams'):
  129. return (Any,) * tp._nparams
  130. return ()
  131. def get_args(tp: Type[Any]) -> Tuple[Any, ...]:
  132. """Get type arguments with all substitutions performed.
  133. For unions, basic simplifications used by Union constructor are performed.
  134. Examples::
  135. get_args(Dict[str, int]) == (str, int)
  136. get_args(int) == ()
  137. get_args(Union[int, Union[T, int], str][int]) == (int, str)
  138. get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int])
  139. get_args(Callable[[], T][int]) == ([], int)
  140. """
  141. if type(tp).__name__ in AnnotatedTypeNames:
  142. return tp.__args__ + tp.__metadata__
  143. # the fallback is needed for the same reasons as `get_origin` (see above)
  144. return _typing_get_args(tp) or getattr(tp, '__args__', ()) or _generic_get_args(tp)
  145. if sys.version_info < (3, 10):
  146. def is_union(tp: Optional[Type[Any]]) -> bool:
  147. return tp is Union
  148. WithArgsTypes = (TypingGenericAlias,)
  149. else:
  150. import types
  151. import typing
  152. def is_union(tp: Optional[Type[Any]]) -> bool:
  153. return tp is Union or tp is types.UnionType # noqa: E721
  154. WithArgsTypes = (typing._GenericAlias, types.GenericAlias, types.UnionType)
  155. if sys.version_info < (3, 9):
  156. StrPath = Union[str, PathLike]
  157. else:
  158. StrPath = Union[str, PathLike]
  159. # TODO: Once we switch to Cython 3 to handle generics properly
  160. # (https://github.com/cython/cython/issues/2753), use following lines instead
  161. # of the one above
  162. # # os.PathLike only becomes subscriptable from Python 3.9 onwards
  163. # StrPath = Union[str, PathLike[str]]
  164. if TYPE_CHECKING:
  165. from .fields import ModelField
  166. TupleGenerator = Generator[Tuple[str, Any], None, None]
  167. DictStrAny = Dict[str, Any]
  168. DictAny = Dict[Any, Any]
  169. SetStr = Set[str]
  170. ListStr = List[str]
  171. IntStr = Union[int, str]
  172. AbstractSetIntStr = AbstractSet[IntStr]
  173. DictIntStrAny = Dict[IntStr, Any]
  174. MappingIntStrAny = Mapping[IntStr, Any]
  175. CallableGenerator = Generator[AnyCallable, None, None]
  176. ReprArgs = Sequence[Tuple[Optional[str], Any]]
  177. AnyClassMethod = classmethod[Any]
  178. __all__ = (
  179. 'ForwardRef',
  180. 'Callable',
  181. 'AnyCallable',
  182. 'NoArgAnyCallable',
  183. 'NoneType',
  184. 'is_none_type',
  185. 'display_as_type',
  186. 'resolve_annotations',
  187. 'is_callable_type',
  188. 'is_literal_type',
  189. 'all_literal_values',
  190. 'is_namedtuple',
  191. 'is_typeddict',
  192. 'is_new_type',
  193. 'new_type_supertype',
  194. 'is_classvar',
  195. 'update_field_forward_refs',
  196. 'update_model_forward_refs',
  197. 'TupleGenerator',
  198. 'DictStrAny',
  199. 'DictAny',
  200. 'SetStr',
  201. 'ListStr',
  202. 'IntStr',
  203. 'AbstractSetIntStr',
  204. 'DictIntStrAny',
  205. 'CallableGenerator',
  206. 'ReprArgs',
  207. 'AnyClassMethod',
  208. 'CallableGenerator',
  209. 'WithArgsTypes',
  210. 'get_args',
  211. 'get_origin',
  212. 'get_sub_types',
  213. 'typing_base',
  214. 'get_all_type_hints',
  215. 'is_union',
  216. 'StrPath',
  217. )
  218. NoneType = None.__class__
  219. NONE_TYPES: Tuple[Any, Any, Any] = (None, NoneType, Literal[None])
  220. if sys.version_info < (3, 8):
  221. # Even though this implementation is slower, we need it for python 3.6/3.7:
  222. # In python 3.6/3.7 "Literal" is not a builtin type and uses a different
  223. # mechanism.
  224. # for this reason `Literal[None] is Literal[None]` evaluates to `False`,
  225. # breaking the faster implementation used for the other python versions.
  226. def is_none_type(type_: Any) -> bool:
  227. return type_ in NONE_TYPES
  228. elif sys.version_info[:2] == (3, 8):
  229. # We can use the fast implementation for 3.8 but there is a very weird bug
  230. # where it can fail for `Literal[None]`.
  231. # We just need to redefine a useless `Literal[None]` inside the function body to fix this
  232. def is_none_type(type_: Any) -> bool:
  233. Literal[None] # fix edge case
  234. for none_type in NONE_TYPES:
  235. if type_ is none_type:
  236. return True
  237. return False
  238. else:
  239. def is_none_type(type_: Any) -> bool:
  240. for none_type in NONE_TYPES:
  241. if type_ is none_type:
  242. return True
  243. return False
  244. def display_as_type(v: Type[Any]) -> str:
  245. if not isinstance(v, typing_base) and not isinstance(v, WithArgsTypes) and not isinstance(v, type):
  246. v = v.__class__
  247. if is_union(get_origin(v)):
  248. return f'Union[{", ".join(map(display_as_type, get_args(v)))}]'
  249. if isinstance(v, WithArgsTypes):
  250. # Generic alias are constructs like `list[int]`
  251. return str(v).replace('typing.', '')
  252. try:
  253. return v.__name__
  254. except AttributeError:
  255. # happens with typing objects
  256. return str(v).replace('typing.', '')
  257. def resolve_annotations(raw_annotations: Dict[str, Type[Any]], module_name: Optional[str]) -> Dict[str, Type[Any]]:
  258. """
  259. Partially taken from typing.get_type_hints.
  260. Resolve string or ForwardRef annotations into type objects if possible.
  261. """
  262. base_globals: Optional[Dict[str, Any]] = None
  263. if module_name:
  264. try:
  265. module = sys.modules[module_name]
  266. except KeyError:
  267. # happens occasionally, see https://github.com/samuelcolvin/pydantic/issues/2363
  268. pass
  269. else:
  270. base_globals = module.__dict__
  271. annotations = {}
  272. for name, value in raw_annotations.items():
  273. if isinstance(value, str):
  274. if (3, 10) > sys.version_info >= (3, 9, 8) or sys.version_info >= (3, 10, 1):
  275. value = ForwardRef(value, is_argument=False, is_class=True)
  276. elif sys.version_info >= (3, 7):
  277. value = ForwardRef(value, is_argument=False)
  278. else:
  279. value = ForwardRef(value)
  280. try:
  281. value = _eval_type(value, base_globals, None)
  282. except NameError:
  283. # this is ok, it can be fixed with update_forward_refs
  284. pass
  285. annotations[name] = value
  286. return annotations
  287. def is_callable_type(type_: Type[Any]) -> bool:
  288. return type_ is Callable or get_origin(type_) is Callable
  289. if sys.version_info >= (3, 7):
  290. def is_literal_type(type_: Type[Any]) -> bool:
  291. return Literal is not None and get_origin(type_) is Literal
  292. def literal_values(type_: Type[Any]) -> Tuple[Any, ...]:
  293. return get_args(type_)
  294. else:
  295. def is_literal_type(type_: Type[Any]) -> bool:
  296. return Literal is not None and hasattr(type_, '__values__') and type_ == Literal[type_.__values__]
  297. def literal_values(type_: Type[Any]) -> Tuple[Any, ...]:
  298. return type_.__values__
  299. def all_literal_values(type_: Type[Any]) -> Tuple[Any, ...]:
  300. """
  301. This method is used to retrieve all Literal values as
  302. Literal can be used recursively (see https://www.python.org/dev/peps/pep-0586)
  303. e.g. `Literal[Literal[Literal[1, 2, 3], "foo"], 5, None]`
  304. """
  305. if not is_literal_type(type_):
  306. return (type_,)
  307. values = literal_values(type_)
  308. return tuple(x for value in values for x in all_literal_values(value))
  309. def is_namedtuple(type_: Type[Any]) -> bool:
  310. """
  311. Check if a given class is a named tuple.
  312. It can be either a `typing.NamedTuple` or `collections.namedtuple`
  313. """
  314. from .utils import lenient_issubclass
  315. return lenient_issubclass(type_, tuple) and hasattr(type_, '_fields')
  316. def is_typeddict(type_: Type[Any]) -> bool:
  317. """
  318. Check if a given class is a typed dict (from `typing` or `typing_extensions`)
  319. In 3.10, there will be a public method (https://docs.python.org/3.10/library/typing.html#typing.is_typeddict)
  320. """
  321. from .utils import lenient_issubclass
  322. return lenient_issubclass(type_, dict) and hasattr(type_, '__total__')
  323. test_type = NewType('test_type', str)
  324. def is_new_type(type_: Type[Any]) -> bool:
  325. """
  326. Check whether type_ was created using typing.NewType
  327. """
  328. return isinstance(type_, test_type.__class__) and hasattr(type_, '__supertype__') # type: ignore
  329. def new_type_supertype(type_: Type[Any]) -> Type[Any]:
  330. while hasattr(type_, '__supertype__'):
  331. type_ = type_.__supertype__
  332. return type_
  333. def _check_classvar(v: Optional[Type[Any]]) -> bool:
  334. if v is None:
  335. return False
  336. return v.__class__ == ClassVar.__class__ and (sys.version_info < (3, 7) or getattr(v, '_name', None) == 'ClassVar')
  337. def is_classvar(ann_type: Type[Any]) -> bool:
  338. return _check_classvar(ann_type) or _check_classvar(get_origin(ann_type))
  339. def update_field_forward_refs(field: 'ModelField', globalns: Any, localns: Any) -> None:
  340. """
  341. Try to update ForwardRefs on fields based on this ModelField, globalns and localns.
  342. """
  343. if field.type_.__class__ == ForwardRef:
  344. field.type_ = evaluate_forwardref(field.type_, globalns, localns or None)
  345. field.prepare()
  346. if field.sub_fields:
  347. for sub_f in field.sub_fields:
  348. update_field_forward_refs(sub_f, globalns=globalns, localns=localns)
  349. if field.discriminator_key is not None:
  350. field.prepare_discriminated_union_sub_fields()
  351. def update_model_forward_refs(
  352. model: Type[Any],
  353. fields: Iterable['ModelField'],
  354. json_encoders: Dict[Union[Type[Any], str], AnyCallable],
  355. localns: 'DictStrAny',
  356. exc_to_suppress: Tuple[Type[BaseException], ...] = (),
  357. ) -> None:
  358. """
  359. Try to update model fields ForwardRefs based on model and localns.
  360. """
  361. if model.__module__ in sys.modules:
  362. globalns = sys.modules[model.__module__].__dict__.copy()
  363. else:
  364. globalns = {}
  365. globalns.setdefault(model.__name__, model)
  366. for f in fields:
  367. try:
  368. update_field_forward_refs(f, globalns=globalns, localns=localns)
  369. except exc_to_suppress:
  370. pass
  371. for key in set(json_encoders.keys()):
  372. if isinstance(key, str):
  373. fr: ForwardRef = ForwardRef(key)
  374. elif isinstance(key, ForwardRef):
  375. fr = key
  376. else:
  377. continue
  378. try:
  379. new_key = evaluate_forwardref(fr, globalns, localns or None)
  380. except exc_to_suppress: # pragma: no cover
  381. continue
  382. json_encoders[new_key] = json_encoders.pop(key)
  383. def get_class(type_: Type[Any]) -> Union[None, bool, Type[Any]]:
  384. """
  385. Tries to get the class of a Type[T] annotation. Returns True if Type is used
  386. without brackets. Otherwise returns None.
  387. """
  388. try:
  389. origin = get_origin(type_)
  390. if origin is None: # Python 3.6
  391. origin = type_
  392. if issubclass(origin, Type): # type: ignore
  393. if not get_args(type_) or not isinstance(get_args(type_)[0], type):
  394. return True
  395. return get_args(type_)[0]
  396. except (AttributeError, TypeError):
  397. pass
  398. return None
  399. def get_sub_types(tp: Any) -> List[Any]:
  400. """
  401. Return all the types that are allowed by type `tp`
  402. `tp` can be a `Union` of allowed types or an `Annotated` type
  403. """
  404. origin = get_origin(tp)
  405. if origin is Annotated:
  406. return get_sub_types(get_args(tp)[0])
  407. elif is_union(origin):
  408. return [x for t in get_args(tp) for x in get_sub_types(t)]
  409. else:
  410. return [tp]