Coverage for pydantic/_internal/_typing_extra.py: 96.90%

319 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-02-13 19:35 +0000

1"""Logic for interacting with type annotations, mostly extensions, shims and hacks to wrap Python's typing module.""" 

2 

3from __future__ import annotations 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

4 

5import collections.abc 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

6import re 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

7import sys 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

8import types 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

9import typing 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

10import warnings 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

11from functools import partial 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

12from typing import TYPE_CHECKING, Any, Callable, cast 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

13from zoneinfo import ZoneInfo 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

14 

15import typing_extensions 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

16from typing_extensions import ParamSpec, TypeAliasType, TypeIs, deprecated, get_args, get_origin 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

17 

18from pydantic.version import version_short 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

19 

20from ._namespace_utils import GlobalsNamespace, MappingNamespace, NsResolver, get_module_ns_of 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

21 

22if sys.version_info < (3, 10): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

23 NoneType = type(None) 1abgcdMef

24 EllipsisType = type(Ellipsis) 1abgFcdMef

25else: 

26 from types import EllipsisType as EllipsisType 1zAtunohiFBCvwpqjkLKHIJGDExyrslm

27 from types import NoneType as NoneType 1zAtunohiFBCvwpqjkLKHIJGDExyrslm

28 

29if TYPE_CHECKING: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

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_t_any = typing.Any 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

38_te_any = typing_extensions.Any 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

39 

40 

41def is_any(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

42 """Return whether the provided argument is the `Any` special form. 

43 

44 ```python {test="skip" lint="skip"} 

45 is_any(Any) 

46 #> True 

47 ``` 

48 """ 

49 return tp is _t_any or tp is _te_any 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

50 

51 

52_t_union = typing.Union 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

53_te_union = typing_extensions.Union 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

54 

55 

56def is_union(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

57 """Return whether the provided argument is a `Union` special form. 

58 

59 ```python {test="skip" lint="skip"} 

60 is_union(Union[int, str]) 

61 #> True 

62 is_union(int | str) 

63 #> False 

64 ``` 

65 """ 

66 origin = get_origin(tp) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

67 return origin is _t_union or origin is _te_union 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

68 

69 

70_t_literal = typing.Literal 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

71_te_literal = typing_extensions.Literal 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

72 

73 

74def is_literal(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

75 """Return whether the provided argument is a `Literal` special form. 

76 

77 ```python {test="skip" lint="skip"} 

78 is_literal(Literal[42]) 

79 #> True 

80 ``` 

81 """ 

82 origin = get_origin(tp) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

83 return origin is _t_literal or origin is _te_literal 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

84 

85 

86def literal_values(tp: Any, /) -> list[Any]: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

87 """Return the values contained in the provided `Literal` special form. 

88 

89 If one of the literal values is a PEP 695 type alias, recursively parse 

90 the type alias' `__value__` to unpack literal values as well. This function 

91 *doesn't* check that the type alias is referencing a `Literal` special form, 

92 so unexpected values could be unpacked. 

93 """ 

94 if not is_literal(tp): 1abzAtunohigFcdBCvwpqjkefDExyrslm

95 # Note: we could also check for generic aliases with a type alias as an origin. 

96 # However, it is very unlikely that this happens as type variables can't appear in 

97 # `Literal` forms, so the only valid (but unnecessary) use case would be something like: 

98 # `type Test[T] = Literal['whatever']` (and then use `Test[SomeType]`). 

99 if is_type_alias_type(tp): 1abzAtunohigFcdBCvwpqjkefDExyrslm

100 # Note: accessing `__value__` could raise a `NameError`, but we just let 

101 # the exception be raised as there's not much we can do if this happens. 

102 return literal_values(tp.__value__) 1abzAtunohigFcdBCvwpqjkefDExyrslm

103 

104 return [tp] 1abzAtunohigFcdBCvwpqjkefDExyrslm

105 

106 values = get_args(tp) 1abzAtunohigFcdBCvwpqjkefDExyrslm

107 return [x for value in values for x in literal_values(value)] 1abzAtunohigFcdBCvwpqjkefDExyrslm

108 

109 

110_t_annotated = typing.Annotated 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

111_te_annotated = typing_extensions.Annotated 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

112 

113 

114def is_annotated(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

115 """Return whether the provided argument is a `Annotated` special form. 

116 

117 ```python {test="skip" lint="skip"} 

118 is_annotated(Annotated[int, ...]) 

119 #> True 

120 ``` 

121 """ 

122 origin = get_origin(tp) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

123 return origin is _t_annotated or origin is _te_annotated 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

124 

125 

126def annotated_type(tp: Any, /) -> Any | None: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

127 """Return the type of the `Annotated` special form, or `None`.""" 

128 return get_args(tp)[0] if is_annotated(tp) else None 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

129 

130 

131def unpack_annotated(annotation: Any, /) -> tuple[Any, list[Any]]: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

132 """Unpack the annotation if it is wrapped with the `Annotated` type qualifier. 

133 

134 This function also unpacks PEP 695 type aliases if necessary (and also generic 

135 aliases with a PEP 695 type alias origin). However, it does *not* try to evaluate 

136 forward references, so users should make sure the type alias' `__value__` does not 

137 contain unresolvable forward references. 

138 

139 Example: 

140 ```python {test="skip" lint="skip"} 

141 from typing import Annotated 

142 

143 type InnerList[T] = Annotated[list[T], 'meta_1'] 

144 type MyList[T] = Annotated[InnerList[T], 'meta_2'] 

145 type MyIntList = MyList[int] 

146 

147 _unpack_annotated(MyList) 

148 #> (list[T], ['meta_1', 'meta_2']) 

149 _unpack_annotated(MyList[int]) 

150 #> (list[int], ['meta_1', 'meta_2']) 

151 _unpack_annotated(MyIntList) 

152 #> (list[int], ['meta_1', 'meta_2']) 

153 ``` 

154 

155 Returns: 

156 A two-tuple, the first element is the annotated type and the second element 

157 is a list containing the annotated metadata. If the annotation wasn't 

158 wrapped with `Annotated` in the first place, it is returned as is and the 

159 metadata list is empty. 

160 """ 

161 if is_annotated(annotation): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

162 typ, *metadata = get_args(annotation) 1abzAtunohigFcdBCvwpqjkefDExyrslm

163 # The annotated type might be a PEP 695 type alias, so we need to recursively 

164 # unpack it. Note that we could make an optimization here: the following next 

165 # call to `_unpack_annotated` could omit the `is_annotated` check, because Python 

166 # already flattens `Annotated[Annotated[<type>, ...], ...]` forms. However, we would 

167 # need to "re-enable" the check for further recursive calls. 

168 typ, sub_meta = unpack_annotated(typ) 1abzAtunohigFcdBCvwpqjkefDExyrslm

169 metadata = sub_meta + metadata 1abzAtunohigFcdBCvwpqjkefDExyrslm

170 return typ, metadata 1abzAtunohigFcdBCvwpqjkefDExyrslm

171 elif is_type_alias_type(annotation): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

172 try: 1abzAtunohigFcdBCvwpqjkefDExyrslm

173 value = annotation.__value__ 1abzAtunohigFcdBCvwpqjkefDExyrslm

174 except NameError: 

175 # The type alias value contains an unresolvable reference. Note that even if it 

176 # resolves successfully, it might contain string annotations, and because of design 

177 # limitations we don't evaluate the type (we don't have access to a `NsResolver` instance). 

178 pass 

179 else: 

180 typ, metadata = unpack_annotated(value) 1abzAtunohigFcdBCvwpqjkefDExyrslm

181 if metadata: 1abzAtunohigFcdBCvwpqjkefDExyrslm

182 # Having metadata means the type alias' `__value__` was an `Annotated` form 

183 # (or, recursively, a type alias to an `Annotated` form). It is important to 

184 # check for this as we don't want to unpack "normal" type aliases (e.g. `type MyInt = int`). 

185 return typ, metadata 1abzAtunohigFcdBCvwpqjkefDExyrslm

186 return annotation, [] 1abzAtunohigFcdBCvwpqjkefDExyrslm

187 elif is_generic_alias(annotation): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

188 # When parametrized, a PEP 695 type alias becomes a generic alias 

189 # (e.g. with `type MyList[T] = Annotated[list[T], ...]`, `MyList[int]` 

190 # is a generic alias). 

191 origin = get_origin(annotation) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

192 if is_type_alias_type(origin): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

193 try: 1abzAtunohigFcdBCvwpqjkefDExyrslm

194 value = origin.__value__ 1abzAtunohigFcdBCvwpqjkefDExyrslm

195 except NameError: 

196 pass 

197 else: 

198 # Circular import (note that these two functions should probably be defined in `_typing_extra`): 

199 from ._generics import get_standard_typevars_map, replace_types 1abzAtunohigFcdBCvwpqjkefDExyrslm

200 

201 # While Python already handles type variable replacement for simple `Annotated` forms, 

202 # we need to manually apply the same logic for PEP 695 type aliases: 

203 # - With `MyList = Annotated[list[T], ...]`, `MyList[int] == Annotated[list[int], ...]` 

204 # - With `type MyList = Annotated[list[T], ...]`, `MyList[int].__value__ == Annotated[list[T], ...]`. 

205 value = replace_types(value, get_standard_typevars_map(annotation)) 1abzAtunohigFcdBCvwpqjkefDExyrslm

206 typ, metadata = unpack_annotated(value) 1abzAtunohigFcdBCvwpqjkefDExyrslm

207 if metadata: 1abzAtunohigFcdBCvwpqjkefDExyrslm

208 return typ, metadata 1abzAtunohigFcdBCvwpqjkefDExyrslm

209 return annotation, [] 1abzAtunohigFcdBCvwpqjkefDExyrslm

210 

211 return annotation, [] 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

212 

213 

214_te_unpack = typing_extensions.Unpack 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

215_te_self = typing_extensions.Self 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

216_te_required = typing_extensions.Required 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

217_te_notrequired = typing_extensions.NotRequired 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

218_te_never = typing_extensions.Never 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

219 

220if sys.version_info >= (3, 11): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

221 _t_unpack = typing.Unpack 1tunohivwpqjkKHIJGxyrslm

222 _t_self = typing.Self 1tunohivwpqjkKHIJGxyrslm

223 _t_required = typing.Required 1tunohivwpqjkKHIJGxyrslm

224 _t_notrequired = typing.NotRequired 1tunohivwpqjkKHIJGxyrslm

225 _t_never = typing.Never 1tunohivwpqjkKHIJGxyrslm

226 

227 def is_unpack(tp: Any, /) -> bool: 1tunohivwpqjkKHIJGxyrslm

228 """Return whether the provided argument is a `Unpack` special form. 

229 

230 ```python {test="skip" lint="skip"} 

231 is_unpack(Unpack[Ts]) 

232 #> True 

233 ``` 

234 """ 

235 origin = get_origin(tp) 1tunohivwpqjkxyrslm

236 return origin is _t_unpack or origin is _te_unpack 1tunohivwpqjkxyrslm

237 

238 def is_self(tp: Any, /) -> bool: 1tunohivwpqjkKHIJGxyrslm

239 """Return whether the provided argument is the `Self` special form. 

240 

241 ```python {test="skip" lint="skip"} 

242 is_self(Self) 

243 #> True 

244 ``` 

245 """ 

246 return tp is _t_self or tp is _te_self 1tunohivwpqjkKHIJGxyrslm

247 

248 def is_required(tp: Any, /) -> bool: 1tunohivwpqjkKHIJGxyrslm

249 """Return whether the provided argument is a `Required` special form. 

250 

251 ```python {test="skip" lint="skip"} 

252 is_required(Required[int]) 

253 #> True 

254 """ 

255 origin = get_origin(tp) 1tunohivwpqjkxyrslm

256 return origin is _t_required or origin is _te_required 1tunohivwpqjkxyrslm

257 

258 def is_not_required(tp: Any, /) -> bool: 1tunohivwpqjkKHIJGxyrslm

259 """Return whether the provided argument is a `NotRequired` special form. 

260 

261 ```python {test="skip" lint="skip"} 

262 is_required(Required[int]) 

263 #> True 

264 """ 

265 origin = get_origin(tp) 1tunohivwpqjkxyrslm

266 return origin is _t_notrequired or origin is _te_notrequired 1tunohivwpqjkxyrslm

267 

268 def is_never(tp: Any, /) -> bool: 1tunohivwpqjkKHIJGxyrslm

269 """Return whether the provided argument is the `Never` special form. 

270 

271 ```python {test="skip" lint="skip"} 

272 is_never(Never) 

273 #> True 

274 ``` 

275 """ 

276 return tp is _t_never or tp is _te_never 1tunohivwpqjkxyrslm

277 

278else: 

279 

280 def is_unpack(tp: Any, /) -> bool: 1abzAgFcdBCMLefDE

281 """Return whether the provided argument is a `Unpack` special form. 

282 

283 ```python {test="skip" lint="skip"} 

284 is_unpack(Unpack[Ts]) 

285 #> True 

286 ``` 

287 """ 

288 origin = get_origin(tp) 1abzAgFcdBCefDE

289 return origin is _te_unpack 1abzAgFcdBCefDE

290 

291 def is_self(tp: Any, /) -> bool: 1abzAgFcdBCMLefDE

292 """Return whether the provided argument is the `Self` special form. 

293 

294 ```python {test="skip" lint="skip"} 

295 is_self(Self) 

296 #> True 

297 ``` 

298 """ 

299 return tp is _te_self 1abzAgFcdBCMLefDE

300 

301 def is_required(tp: Any, /) -> bool: 1abzAgFcdBCMLefDE

302 """Return whether the provided argument is a `Required` special form. 

303 

304 ```python {test="skip" lint="skip"} 

305 is_required(Required[int]) 

306 #> True 

307 """ 

308 origin = get_origin(tp) 1abzAgFcdBCefDE

309 return origin is _te_required 1abzAgFcdBCefDE

310 

311 def is_not_required(tp: Any, /) -> bool: 1abzAgFcdBCMLefDE

312 """Return whether the provided argument is a `NotRequired` special form. 

313 

314 ```python {test="skip" lint="skip"} 

315 is_required(Required[int]) 

316 #> True 

317 """ 

318 origin = get_origin(tp) 1abzAgFcdBCefDE

319 return origin is _te_notrequired 1abzAgFcdBCefDE

320 

321 def is_never(tp: Any, /) -> bool: 1abzAgFcdBCMLefDE

322 """Return whether the provided argument is the `Never` special form. 

323 

324 ```python {test="skip" lint="skip"} 

325 is_never(Never) 

326 #> True 

327 ``` 

328 """ 

329 return tp is _te_never 1abzAgFcdBCefDE

330 

331 

332def unpack_type(tp: Any, /) -> Any | None: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

333 """Return the type wrapped by the `Unpack` special form, or `None`.""" 

334 return get_args(tp)[0] if is_unpack(tp) else None 1abzAtunohigFcdBCvwpqjkefDExyrslm

335 

336 

337def is_new_type(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

338 """Return whether the provided argument is a `NewType`. 

339 

340 ```python {test="skip" lint="skip"} 

341 is_new_type(NewType('MyInt', int)) 

342 #> True 

343 ``` 

344 """ 

345 if sys.version_info < (3, 10): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

346 # On Python < 3.10, `typing.NewType` is a function 

347 return hasattr(tp, '__supertype__') 1abgcdMef

348 else: 

349 return type(tp) is typing.NewType or type(tp) is typing_extensions.NewType 1zAtunohiFBCvwpqjkLKHIJGDExyrslm

350 

351 

352def is_hashable(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

353 """Return whether the provided argument is the `Hashable` class. 

354 

355 ```python {test="skip" lint="skip"} 

356 is_hashable(Hashable) 

357 #> True 

358 ``` 

359 """ 

360 # `get_origin` is documented as normalizing any typing-module aliases to `collections` classes, 

361 # hence the second check: 

362 return tp is collections.abc.Hashable or get_origin(tp) is collections.abc.Hashable 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

363 

364 

365def is_callable(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

366 """Return whether the provided argument is a `Callable`, parametrized or not. 

367 

368 ```python {test="skip" lint="skip"} 

369 is_callable(Callable[[int], str]) 

370 #> True 

371 is_callable(typing.Callable) 

372 #> True 

373 is_callable(collections.abc.Callable) 

374 #> True 

375 ``` 

376 """ 

377 # `get_origin` is documented as normalizing any typing-module aliases to `collections` classes, 

378 # hence the second check: 

379 return tp is collections.abc.Callable or get_origin(tp) is collections.abc.Callable 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

380 

381 

382_PARAMSPEC_TYPES: tuple[type[ParamSpec], ...] = (typing_extensions.ParamSpec,) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

383if sys.version_info >= (3, 10): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

384 _PARAMSPEC_TYPES = (*_PARAMSPEC_TYPES, typing.ParamSpec) # pyright: ignore[reportAssignmentType] 1zAtunohiFBCvwpqjkLKHIJGDExyrslm

385 

386 

387def is_paramspec(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

388 """Return whether the provided argument is a `ParamSpec`. 

389 

390 ```python {test="skip" lint="skip"} 

391 P = ParamSpec('P') 

392 is_paramspec(P) 

393 #> True 

394 ``` 

395 """ 

396 return isinstance(tp, _PARAMSPEC_TYPES) 

397 

398 

399_TYPE_ALIAS_TYPES: tuple[type[TypeAliasType], ...] = (typing_extensions.TypeAliasType,) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

400if sys.version_info >= (3, 12): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

401 _TYPE_ALIAS_TYPES = (*_TYPE_ALIAS_TYPES, typing.TypeAliasType) 1nohipqjkHIJGrslm

402 

403_IS_PY310 = sys.version_info[:2] == (3, 10) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

404 

405 

406def is_type_alias_type(tp: Any, /) -> TypeIs[TypeAliasType]: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

407 """Return whether the provided argument is an instance of `TypeAliasType`. 

408 

409 ```python {test="skip" lint="skip"} 

410 type Int = int 

411 is_type_alias_type(Int) 

412 #> True 

413 Str = TypeAliasType('Str', str) 

414 is_type_alias_type(Str) 

415 #> True 

416 ``` 

417 """ 

418 if _IS_PY310: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

419 # Parametrized PEP 695 type aliases are instances of `types.GenericAlias` in typing_extensions>=4.13.0. 

420 # On Python 3.10, with `Alias[int]` being such an instance of `GenericAlias`, 

421 # `isinstance(Alias[int], TypeAliasType)` returns `True`. 

422 # See https://github.com/python/cpython/issues/89828. 

423 return type(tp) is not types.GenericAlias and isinstance(tp, _TYPE_ALIAS_TYPES) 1zAFBCLDE

424 else: 

425 return isinstance(tp, _TYPE_ALIAS_TYPES) 1abtunohigcdvwpqjkMKHIJGefxyrslm

426 

427 

428_t_classvar = typing.ClassVar 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

429_te_classvar = typing_extensions.ClassVar 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

430 

431 

432def is_classvar(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

433 """Return whether the provided argument is a `ClassVar` special form, parametrized or not. 

434 

435 Note that in most cases, you will want to use the `is_classvar_annotation` function, 

436 which is used to check if an annotation (in the context of a Pydantic model or dataclass) 

437 should be treated as being a class variable. 

438 

439 ```python {test="skip" lint="skip"} 

440 is_classvar(ClassVar[int]) 

441 #> True 

442 is_classvar(ClassVar) 

443 #> True 

444 """ 

445 # ClassVar is not necessarily parametrized: 

446 if tp is _t_classvar or tp is _te_classvar: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

447 return True 1abzAtunohigFcdBCvwpqjkefDExyrslm

448 origin = get_origin(tp) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

449 return origin is _t_classvar or origin is _te_classvar 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

450 

451 

452_classvar_re = re.compile(r'((\w+\.)?Annotated\[)?(\w+\.)?ClassVar\[') 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

453 

454 

455def is_classvar_annotation(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

456 """Return whether the provided argument represents a class variable annotation. 

457 

458 Although not explicitly stated by the typing specification, `ClassVar` can be used 

459 inside `Annotated` and as such, this function checks for this specific scenario. 

460 

461 Because this function is used to detect class variables before evaluating forward references 

462 (or because evaluation failed), we also implement a naive regex match implementation. This is 

463 required because class variables are inspected before fields are collected, so we try to be 

464 as accurate as possible. 

465 """ 

466 if is_classvar(tp) or (anntp := annotated_type(tp)) is not None and is_classvar(anntp): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

467 return True 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

468 

469 str_ann: str | None = None 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

470 if isinstance(tp, typing.ForwardRef): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

471 str_ann = tp.__forward_arg__ 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

472 if isinstance(tp, str): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

473 str_ann = tp 1abzAtunohigFcdBCvwpqjkefDExyrslm

474 

475 if str_ann is not None and _classvar_re.match(str_ann): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

476 # stdlib dataclasses do something similar, although a bit more advanced 

477 # (see `dataclass._is_type`). 

478 return True 1abzAtunohigFcdBCvwpqjkefDExyrslm

479 

480 return False 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

481 

482 

483_t_final = typing.Final 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

484_te_final = typing_extensions.Final 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

485 

486 

487# TODO implement `is_finalvar_annotation` as Final can be wrapped with other special forms: 

488def is_finalvar(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

489 """Return whether the provided argument is a `Final` special form, parametrized or not. 

490 

491 ```python {test="skip" lint="skip"} 

492 is_finalvar(Final[int]) 

493 #> True 

494 is_finalvar(Final) 

495 #> True 

496 """ 

497 # Final is not necessarily parametrized: 

498 if tp is _t_final or tp is _te_final: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

499 return True 1abzAtunohigFcdBCvwpqjkefDExyrslm

500 origin = get_origin(tp) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

501 return origin is _t_final or origin is _te_final 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

502 

503 

504_t_noreturn = typing.NoReturn 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

505_te_noreturn = typing_extensions.NoReturn 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

506 

507 

508def is_no_return(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

509 """Return whether the provided argument is the `NoReturn` special form. 

510 

511 ```python {test="skip" lint="skip"} 

512 is_no_return(NoReturn) 

513 #> True 

514 ``` 

515 """ 

516 return tp is _t_noreturn or tp is _te_noreturn 1abzAtunohigFcdBCvwpqjkefDExyrslm

517 

518 

519_DEPRECATED_TYPES: tuple[type[deprecated], ...] = (typing_extensions.deprecated,) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

520if hasattr(warnings, 'deprecated'): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

521 _DEPRECATED_TYPES = (*_DEPRECATED_TYPES, warnings.deprecated) # pyright: ignore[reportAttributeAccessIssue] 1hijkGlm

522 

523 

524def is_deprecated_instance(obj: Any, /) -> TypeIs[deprecated]: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

525 """Return whether the argument is an instance of the `warnings.deprecated` class or the `typing_extensions` backport.""" 

526 return isinstance(obj, _DEPRECATED_TYPES) 1abzAtunohigFcdBCvwpqjkefDExyrslm

527 

528 

529_NONE_TYPES: tuple[Any, ...] = (None, NoneType, typing.Literal[None], typing_extensions.Literal[None]) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

530 

531 

532def is_none_type(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

533 """Return whether the argument represents the `None` type as part of an annotation. 

534 

535 ```python {test="skip" lint="skip"} 

536 is_none_type(None) 

537 #> True 

538 is_none_type(NoneType) 

539 #> True 

540 is_none_type(Literal[None]) 

541 #> True 

542 is_none_type(type[None]) 

543 #> False 

544 """ 

545 return tp in _NONE_TYPES 1abzAtunohigFcdBCvwpqjkefDExyrslm

546 

547 

548def is_namedtuple(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

549 """Return whether the provided argument is a named tuple class. 

550 

551 The class can be created using `typing.NamedTuple` or `collections.namedtuple`. 

552 Parametrized generic classes are *not* assumed to be named tuples. 

553 """ 

554 from ._utils import lenient_issubclass # circ. import 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

555 

556 return lenient_issubclass(tp, tuple) and hasattr(tp, '_fields') 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

557 

558 

559def is_zoneinfo_type(tp: Any, /) -> TypeIs[type[ZoneInfo]]: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

560 """Return whether the provided argument is the `zoneinfo.ZoneInfo` type.""" 

561 return tp is ZoneInfo 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

562 

563 

564_t_union = typing.Union 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

565_te_union = typing_extensions.Union 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

566 

567_t_union = typing.Union 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

568_te_union = typing_extensions.Union 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

569 

570if sys.version_info < (3, 10): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

571 

572 def origin_is_union(tp: Any, /) -> bool: 1abgcdMef

573 """Return whether the provided argument is the `Union` special form.""" 

574 return tp is _t_union or tp is _te_union 1abgcdMef

575 

576else: 

577 

578 def origin_is_union(tp: Any, /) -> bool: 1zAtunohiFBCvwpqjkLKHIJGDExyrslm

579 """Return whether the provided argument is the `Union` special form or the `UnionType`.""" 

580 return tp is _t_union or tp is _te_union or tp is types.UnionType 1zAtunohiFBCvwpqjkLKHIJGDExyrslm

581 

582 

583def is_generic_alias(tp: Any, /) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

584 return isinstance(tp, (types.GenericAlias, typing._GenericAlias)) # pyright: ignore[reportAttributeAccessIssue] 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

585 

586 

587# TODO: Ideally, we should avoid relying on the private `typing` constructs: 

588 

589if sys.version_info < (3, 10): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

590 WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias) # pyright: ignore[reportAttributeAccessIssue] 1abgcdMef

591else: 

592 WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias, types.UnionType) # pyright: ignore[reportAttributeAccessIssue] 1zAtunohiFBCvwpqjkLKHIJGDExyrslm

593 

594 

595# Similarly, we shouldn't rely on this `_Final` class, which is even more private than `_GenericAlias`: 

596typing_base: Any = typing._Final # pyright: ignore[reportAttributeAccessIssue] 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

597 

598 

599### Annotation evaluations functions: 

600 

601 

602def parent_frame_namespace(*, parent_depth: int = 2, force: bool = False) -> dict[str, Any] | None: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

603 """Fetch the local namespace of the parent frame where this function is called. 

604 

605 Using this function is mostly useful to resolve forward annotations pointing to members defined in a local namespace, 

606 such as assignments inside a function. Using the standard library tools, it is currently not possible to resolve 

607 such annotations: 

608 

609 ```python {lint="skip" test="skip"} 

610 from typing import get_type_hints 

611 

612 def func() -> None: 

613 Alias = int 

614 

615 class C: 

616 a: 'Alias' 

617 

618 # Raises a `NameError: 'Alias' is not defined` 

619 get_type_hints(C) 

620 ``` 

621 

622 Pydantic uses this function when a Pydantic model is being defined to fetch the parent frame locals. However, 

623 this only allows us to fetch the parent frame namespace and not other parents (e.g. a model defined in a function, 

624 itself defined in another function). Inspecting the next outer frames (using `f_back`) is not reliable enough 

625 (see https://discuss.python.org/t/20659). 

626 

627 Because this function is mostly used to better resolve forward annotations, nothing is returned if the parent frame's 

628 code object is defined at the module level. In this case, the locals of the frame will be the same as the module 

629 globals where the class is defined (see `_namespace_utils.get_module_ns_of`). However, if you still want to fetch 

630 the module globals (e.g. when rebuilding a model, where the frame where the rebuild call is performed might contain 

631 members that you want to use for forward annotations evaluation), you can use the `force` parameter. 

632 

633 Args: 

634 parent_depth: The depth at which to get the frame. Defaults to 2, meaning the parent frame where this function 

635 is called will be used. 

636 force: Whether to always return the frame locals, even if the frame's code object is defined at the module level. 

637 

638 Returns: 

639 The locals of the namespace, or `None` if it was skipped as per the described logic. 

640 """ 

641 frame = sys._getframe(parent_depth) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

642 

643 if frame.f_code.co_name.startswith('<generic parameters of'): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

644 # As `parent_frame_namespace` is mostly called in `ModelMetaclass.__new__`, 

645 # the parent frame can be the annotation scope if the PEP 695 generic syntax is used. 

646 # (see https://docs.python.org/3/reference/executionmodel.html#annotation-scopes, 

647 # https://docs.python.org/3/reference/compound_stmts.html#generic-classes). 

648 # In this case, the code name is set to `<generic parameters of MyClass>`, 

649 # and we need to skip this frame as it is irrelevant. 

650 frame = cast(types.FrameType, frame.f_back) # guaranteed to not be `None` 1nohipqjkrslm

651 

652 # note, we don't copy frame.f_locals here (or during the last return call), because we don't expect the namespace to be 

653 # modified down the line if this becomes a problem, we could implement some sort of frozen mapping structure to enforce this. 

654 if force: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

655 return frame.f_locals 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

656 

657 # If either of the following conditions are true, the class is defined at the top module level. 

658 # To better understand why we need both of these checks, see 

659 # https://github.com/pydantic/pydantic/pull/10113#discussion_r1714981531. 

660 if frame.f_back is None or frame.f_code.co_name == '<module>': 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

661 return None 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

662 

663 return frame.f_locals 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

664 

665 

666def _type_convert(arg: Any) -> Any: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

667 """Convert `None` to `NoneType` and strings to `ForwardRef` instances. 

668 

669 This is a backport of the private `typing._type_convert` function. When 

670 evaluating a type, `ForwardRef._evaluate` ends up being called, and is 

671 responsible for making this conversion. However, we still have to apply 

672 it for the first argument passed to our type evaluation functions, similarly 

673 to the `typing.get_type_hints` function. 

674 """ 

675 if arg is None: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

676 return NoneType 1abzAtunohigFcdBCvwpqjkefDExyrslm

677 if isinstance(arg, str): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

678 # Like `typing.get_type_hints`, assume the arg can be in any context, 

679 # hence the proper `is_argument` and `is_class` args: 

680 return _make_forward_ref(arg, is_argument=False, is_class=True) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

681 return arg 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

682 

683 

684def get_model_type_hints( 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

685 obj: type[BaseModel], 

686 *, 

687 ns_resolver: NsResolver | None = None, 

688) -> dict[str, tuple[Any, bool]]: 

689 """Collect annotations from a Pydantic model class, including those from parent classes. 

690 

691 Args: 

692 obj: The Pydantic model to inspect. 

693 ns_resolver: A namespace resolver instance to use. Defaults to an empty instance. 

694 

695 Returns: 

696 A dictionary mapping annotation names to a two-tuple: the first element is the evaluated 

697 type or the original annotation if a `NameError` occurred, the second element is a boolean 

698 indicating if whether the evaluation succeeded. 

699 """ 

700 hints: dict[str, Any] | dict[str, tuple[Any, bool]] = {} 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

701 ns_resolver = ns_resolver or NsResolver() 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

702 

703 for base in reversed(obj.__mro__): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

704 ann: dict[str, Any] | None = base.__dict__.get('__annotations__') 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

705 if not ann or isinstance(ann, types.GetSetDescriptorType): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

706 continue 1zAtunohiFBCvwpqjkLKHIJGDExyrslm

707 with ns_resolver.push(base): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

708 globalns, localns = ns_resolver.types_namespace 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

709 for name, value in ann.items(): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

710 if name.startswith('_'): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

711 # For private attributes, we only need the annotation to detect the `ClassVar` special form. 

712 # For this reason, we still try to evaluate it, but we also catch any possible exception (on 

713 # top of the `NameError`s caught in `try_eval_type`) that could happen so that users are free 

714 # to use any kind of forward annotation for private fields (e.g. circular imports, new typing 

715 # syntax, etc). 

716 try: 1abzAtunohigFcdBCvwpqjkefDExyrslm

717 hints[name] = try_eval_type(value, globalns, localns) 1abzAtunohigFcdBCvwpqjkefDExyrslm

718 except Exception: 1abzAtunohigFcdBCvwpqjkefDExyrslm

719 hints[name] = (value, False) 1abzAtunohigFcdBCvwpqjkefDExyrslm

720 else: 

721 hints[name] = try_eval_type(value, globalns, localns) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

722 return hints 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

723 

724 

725def get_cls_type_hints( 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

726 obj: type[Any], 

727 *, 

728 ns_resolver: NsResolver | None = None, 

729) -> dict[str, Any]: 

730 """Collect annotations from a class, including those from parent classes. 

731 

732 Args: 

733 obj: The class to inspect. 

734 ns_resolver: A namespace resolver instance to use. Defaults to an empty instance. 

735 """ 

736 hints: dict[str, Any] | dict[str, tuple[Any, bool]] = {} 1abzAtunohigFcdBCvwpqjkefDExyrslm

737 ns_resolver = ns_resolver or NsResolver() 1abzAtunohigFcdBCvwpqjkefDExyrslm

738 

739 for base in reversed(obj.__mro__): 1abzAtunohigFcdBCvwpqjkefDExyrslm

740 ann: dict[str, Any] | None = base.__dict__.get('__annotations__') 1abzAtunohigFcdBCvwpqjkefDExyrslm

741 if not ann or isinstance(ann, types.GetSetDescriptorType): 1abzAtunohigFcdBCvwpqjkefDExyrslm

742 continue 1zAtunohiFBCvwpqjkDExyrslm

743 with ns_resolver.push(base): 1abzAtunohigFcdBCvwpqjkefDExyrslm

744 globalns, localns = ns_resolver.types_namespace 1abzAtunohigFcdBCvwpqjkefDExyrslm

745 for name, value in ann.items(): 1abzAtunohigFcdBCvwpqjkefDExyrslm

746 hints[name] = eval_type(value, globalns, localns) 1abzAtunohigFcdBCvwpqjkefDExyrslm

747 return hints 1abzAtunohigFcdBCvwpqjkefDExyrslm

748 

749 

750def try_eval_type( 1abzAtunohicdBCvwpqjkMLKHIJGefDExyrslm

751 value: Any, 

752 globalns: GlobalsNamespace | None = None, 

753 localns: MappingNamespace | None = None, 

754) -> tuple[Any, bool]: 

755 """Try evaluating the annotation using the provided namespaces. 

756 

757 Args: 

758 value: The value to evaluate. If `None`, it will be replaced by `type[None]`. If an instance 

759 of `str`, it will be converted to a `ForwardRef`. 

760 localns: The global namespace to use during annotation evaluation. 

761 globalns: The local namespace to use during annotation evaluation. 

762 

763 Returns: 

764 A two-tuple containing the possibly evaluated type and a boolean indicating 

765 whether the evaluation succeeded or not. 

766 """ 

767 value = _type_convert(value) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

768 

769 try: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

770 return eval_type_backport(value, globalns, localns), True 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

771 except NameError: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

772 return value, False 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

773 

774 

775def eval_type( 1abzAtunohicdBCvwpqjkMLKHIJGefDExyrslm

776 value: Any, 

777 globalns: GlobalsNamespace | None = None, 

778 localns: MappingNamespace | None = None, 

779) -> Any: 

780 """Evaluate the annotation using the provided namespaces. 

781 

782 Args: 

783 value: The value to evaluate. If `None`, it will be replaced by `type[None]`. If an instance 

784 of `str`, it will be converted to a `ForwardRef`. 

785 localns: The global namespace to use during annotation evaluation. 

786 globalns: The local namespace to use during annotation evaluation. 

787 """ 

788 value = _type_convert(value) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

789 return eval_type_backport(value, globalns, localns) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

790 

791 

792@deprecated( 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

793 '`eval_type_lenient` is deprecated, use `try_eval_type` instead.', 

794 category=None, 

795) 

796def eval_type_lenient( 1abzAtunohicdBCvwpqjkMLKHIJGefDExyrslm

797 value: Any, 

798 globalns: GlobalsNamespace | None = None, 

799 localns: MappingNamespace | None = None, 

800) -> Any: 

801 ev, _ = try_eval_type(value, globalns, localns) 

802 return ev 

803 

804 

805def eval_type_backport( 1abzAtunohicdBCvwpqjkMLKHIJGefDExyrslm

806 value: Any, 

807 globalns: GlobalsNamespace | None = None, 

808 localns: MappingNamespace | None = None, 

809 type_params: tuple[Any, ...] | None = None, 

810) -> Any: 

811 """An enhanced version of `typing._eval_type` which will fall back to using the `eval_type_backport` 

812 package if it's installed to let older Python versions use newer typing constructs. 

813 

814 Specifically, this transforms `X | Y` into `typing.Union[X, Y]` and `list[X]` into `typing.List[X]` 

815 (as well as all the types made generic in PEP 585) if the original syntax is not supported in the 

816 current Python version. 

817 

818 This function will also display a helpful error if the value passed fails to evaluate. 

819 """ 

820 try: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

821 return _eval_type_backport(value, globalns, localns, type_params) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

822 except TypeError as e: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

823 if 'Unable to evaluate type annotation' in str(e): 1abzAtunohigFcdBCvwpqjkefDExyrslm

824 raise 1abgcdef

825 

826 # If it is a `TypeError` and value isn't a `ForwardRef`, it would have failed during annotation definition. 

827 # Thus we assert here for type checking purposes: 

828 assert isinstance(value, typing.ForwardRef) 1abzAtunohigFcdBCvwpqjkefDExyrslm

829 

830 message = f'Unable to evaluate type annotation {value.__forward_arg__!r}.' 1abzAtunohigFcdBCvwpqjkefDExyrslm

831 if sys.version_info >= (3, 11): 1abzAtunohigFcdBCvwpqjkefDExyrslm

832 e.add_note(message) 1tunohivwpqjkxyrslm

833 raise 1tunohivwpqjkxyrslm

834 else: 

835 raise TypeError(message) from e 1abzAgFcdBCefDE

836 except RecursionError as e: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

837 # TODO ideally recursion errors should be checked in `eval_type` above, but `eval_type_backport` 

838 # is used directly in some places. 

839 message = ( 1abzAtunohicdBCvwpqjkefDExyrslm

840 "If you made use of an implicit recursive type alias (e.g. `MyType = list['MyType']), " 

841 'consider using PEP 695 type aliases instead. For more details, refer to the documentation: ' 

842 f'https://docs.pydantic.dev/{version_short()}/concepts/types/#named-recursive-types' 

843 ) 

844 if sys.version_info >= (3, 11): 1abzAtunohicdBCvwpqjkefDExyrslm

845 e.add_note(message) 1tunohivwpqjkxyrslm

846 raise 1tunohivwpqjkxyrslm

847 else: 

848 raise RecursionError(f'{e.args[0]}\n{message}') 1abzAcdBCefDE

849 

850 

851def _eval_type_backport( 1abzAtunohicdBCvwpqjkMLKHIJGefDExyrslm

852 value: Any, 

853 globalns: GlobalsNamespace | None = None, 

854 localns: MappingNamespace | None = None, 

855 type_params: tuple[Any, ...] | None = None, 

856) -> Any: 

857 try: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

858 return _eval_type(value, globalns, localns, type_params) 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

859 except TypeError as e: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

860 if not (isinstance(value, typing.ForwardRef) and is_backport_fixable_error(e)): 1abzAtunohigFcdBCvwpqjkefDExyrslm

861 raise 1abzAtunohigFcdBCvwpqjkefDExyrslm

862 

863 try: 1abgcdef

864 from eval_type_backport import eval_type_backport 1abgcdef

865 except ImportError: 1abgcdef

866 raise TypeError( 1abgcdef

867 f'Unable to evaluate type annotation {value.__forward_arg__!r}. If you are making use ' 

868 'of the new typing syntax (unions using `|` since Python 3.10 or builtins subscripting ' 

869 'since Python 3.9), you should either replace the use of new syntax with the existing ' 

870 '`typing` constructs or install the `eval_type_backport` package.' 

871 ) from e 

872 

873 return eval_type_backport( 1abgcdef

874 value, 

875 globalns, 

876 localns, # pyright: ignore[reportArgumentType], waiting on a new `eval_type_backport` release. 

877 try_default=False, 

878 ) 

879 

880 

881def _eval_type( 1abzAtunohicdBCvwpqjkMLKHIJGefDExyrslm

882 value: Any, 

883 globalns: GlobalsNamespace | None = None, 

884 localns: MappingNamespace | None = None, 

885 type_params: tuple[Any, ...] | None = None, 

886) -> Any: 

887 if sys.version_info >= (3, 13): 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

888 return typing._eval_type( # type: ignore 1hijkGlm

889 value, globalns, localns, type_params=type_params 

890 ) 

891 else: 

892 return typing._eval_type( # type: ignore 1abzAtunogFcdBCvwpqMLKHIJefDExyrs

893 value, globalns, localns 

894 ) 

895 

896 

897def is_backport_fixable_error(e: TypeError) -> bool: 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

898 msg = str(e) 1abzAtunohigFcdBCvwpqjkefDExyrslm

899 

900 return sys.version_info < (3, 10) and msg.startswith('unsupported operand type(s) for |: ') 1abzAtunohigFcdBCvwpqjkefDExyrslm

901 

902 

903def get_function_type_hints( 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

904 function: Callable[..., Any], 

905 *, 

906 include_keys: set[str] | None = None, 

907 globalns: GlobalsNamespace | None = None, 

908 localns: MappingNamespace | None = None, 

909) -> dict[str, Any]: 

910 """Return type hints for a function. 

911 

912 This is similar to the `typing.get_type_hints` function, with a few differences: 

913 - Support `functools.partial` by using the underlying `func` attribute. 

914 - If `function` happens to be a built-in type (e.g. `int`), assume it doesn't have annotations 

915 but specify the `return` key as being the actual type. 

916 - Do not wrap type annotation of a parameter with `Optional` if it has a default value of `None` 

917 (related bug: https://github.com/python/cpython/issues/90353, only fixed in 3.11+). 

918 """ 

919 try: 1abzAtunohigFcdBCvwpqjkefDExyrslm

920 if isinstance(function, partial): 1abzAtunohigFcdBCvwpqjkefDExyrslm

921 annotations = function.func.__annotations__ 1abzAtunohigFcdBCvwpqjkefDExyrslm

922 else: 

923 annotations = function.__annotations__ 1abzAtunohigFcdBCvwpqjkefDExyrslm

924 except AttributeError: 1abzAtunohigFcdBCvwpqjkefDExyrslm

925 type_hints = get_type_hints(function) 1abzAtunohigFcdBCvwpqjkefDExyrslm

926 if isinstance(function, type): 926 ↛ 931line 926 didn't jump to line 931 because the condition on line 926 was always true1abzAtunohigFcdBCvwpqjkefDExyrslm

927 # `type[...]` is a callable, which returns an instance of itself. 

928 # At some point, we might even look into the return type of `__new__` 

929 # if it returns something else. 

930 type_hints.setdefault('return', function) 1abzAtunohigFcdBCvwpqjkefDExyrslm

931 return type_hints 1abzAtunohigFcdBCvwpqjkefDExyrslm

932 

933 if globalns is None: 1abzAtunohigFcdBCvwpqjkefDExyrslm

934 globalns = get_module_ns_of(function) 1abzAtunohigFcdBCvwpqjkefDExyrslm

935 type_params: tuple[Any, ...] | None = None 1abzAtunohigFcdBCvwpqjkefDExyrslm

936 if localns is None: 1abzAtunohigFcdBCvwpqjkefDExyrslm

937 # If localns was specified, it is assumed to already contain type params. This is because 

938 # Pydantic has more advanced logic to do so (see `_namespace_utils.ns_for_function`). 

939 type_params = getattr(function, '__type_params__', ()) 1abzAtunohigFcdBCvwpqjkefDExyrslm

940 

941 type_hints = {} 1abzAtunohigFcdBCvwpqjkefDExyrslm

942 for name, value in annotations.items(): 1abzAtunohigFcdBCvwpqjkefDExyrslm

943 if include_keys is not None and name not in include_keys: 1abzAtunohigFcdBCvwpqjkefDExyrslm

944 continue 1abzAtunohigFcdBCvwpqjkefDExyrslm

945 if value is None: 1abzAtunohigFcdBCvwpqjkefDExyrslm

946 value = NoneType 1abzAtunohigFcdBCvwpqjkefDExyrslm

947 elif isinstance(value, str): 1abzAtunohigFcdBCvwpqjkefDExyrslm

948 value = _make_forward_ref(value) 1abzAtunohigFcdBCvwpqjkefDExyrslm

949 

950 type_hints[name] = eval_type_backport(value, globalns, localns, type_params) 1abzAtunohigFcdBCvwpqjkefDExyrslm

951 

952 return type_hints 1abzAtunohigFcdBCvwpqjkefDExyrslm

953 

954 

955if sys.version_info < (3, 9, 8) or (3, 10) <= sys.version_info < (3, 10, 1): 955 ↛ 957line 955 didn't jump to line 957 because the condition on line 955 was never true1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

956 

957 def _make_forward_ref( 

958 arg: Any, 

959 is_argument: bool = True, 

960 *, 

961 is_class: bool = False, 

962 ) -> typing.ForwardRef: 

963 """Wrapper for ForwardRef that accounts for the `is_class` argument missing in older versions. 

964 The `module` argument is omitted as it breaks <3.9.8, =3.10.0 and isn't used in the calls below. 

965 

966 See https://github.com/python/cpython/pull/28560 for some background. 

967 The backport happened on 3.9.8, see: 

968 https://github.com/pydantic/pydantic/discussions/6244#discussioncomment-6275458, 

969 and on 3.10.1 for the 3.10 branch, see: 

970 https://github.com/pydantic/pydantic/issues/6912 

971 

972 Implemented as EAFP with memory. 

973 """ 

974 return typing.ForwardRef(arg, is_argument) 

975 

976else: 

977 _make_forward_ref = typing.ForwardRef 1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

978 

979 

980if sys.version_info >= (3, 10): 980 ↛ 984line 980 didn't jump to line 984 because the condition on line 980 was always true1abzAtunohigFcdBCvwpqjkMLKHIJGefDExyrslm

981 get_type_hints = typing.get_type_hints 1zAtunohiFBCvwpqjkLKHIJGDExyrslm

982 

983else: 

984 """ 

985 For older versions of python, we have a custom implementation of `get_type_hints` which is a close as possible to 

986 the implementation in CPython 3.10.8. 

987 """ 

988 

989 @typing.no_type_check 1abgcdMef

990 def get_type_hints( # noqa: C901 1abcdMef

991 obj: Any, 1g

992 globalns: dict[str, Any] | None = None, 1g

993 localns: dict[str, Any] | None = None, 1g

994 include_extras: bool = False, 1g

995 ) -> dict[str, Any]: # pragma: no cover 1g

996 """Taken verbatim from python 3.10.8 unchanged, except: 

997 * type annotations of the function definition above. 

998 * prefixing `typing.` where appropriate 

999 * Use `_make_forward_ref` instead of `typing.ForwardRef` to handle the `is_class` argument. 

1000 

1001 https://github.com/python/cpython/blob/aaaf5174241496afca7ce4d4584570190ff972fe/Lib/typing.py#L1773-L1875 

1002 

1003 DO NOT CHANGE THIS METHOD UNLESS ABSOLUTELY NECESSARY. 

1004 ====================================================== 

1005 

1006 Return type hints for an object. 

1007 

1008 This is often the same as obj.__annotations__, but it handles 

1009 forward references encoded as string literals, adds Optional[t] if a 

1010 default value equal to None is set and recursively replaces all 

1011 'Annotated[T, ...]' with 'T' (unless 'include_extras=True'). 

1012 

1013 The argument may be a module, class, method, or function. The annotations 

1014 are returned as a dictionary. For classes, annotations include also 

1015 inherited members. 

1016 

1017 TypeError is raised if the argument is not of a type that can contain 

1018 annotations, and an empty dictionary is returned if no annotations are 

1019 present. 

1020 

1021 BEWARE -- the behavior of globalns and localns is counterintuitive 

1022 (unless you are familiar with how eval() and exec() work). The 

1023 search order is locals first, then globals. 

1024 

1025 - If no dict arguments are passed, an attempt is made to use the 

1026 globals from obj (or the respective module's globals for classes), 

1027 and these are also used as the locals. If the object does not appear 

1028 to have globals, an empty dictionary is used. For classes, the search 

1029 order is globals first then locals. 

1030 

1031 - If one dict argument is passed, it is used for both globals and 

1032 locals. 

1033 

1034 - If two dict arguments are passed, they specify globals and 

1035 locals, respectively. 

1036 """ 

1037 if getattr(obj, '__no_type_check__', None): 1abgcdef

1038 return {} 

1039 # Classes require a special treatment. 

1040 if isinstance(obj, type): 1abgcdef

1041 hints = {} 1abgcdef

1042 for base in reversed(obj.__mro__): 1abgcdef

1043 if globalns is None: 1abgcdef

1044 base_globals = getattr(sys.modules.get(base.__module__, None), '__dict__', {}) 1abgcdef

1045 else: 

1046 base_globals = globalns 

1047 ann = base.__dict__.get('__annotations__', {}) 1abgcdef

1048 if isinstance(ann, types.GetSetDescriptorType): 1abgcdef

1049 ann = {} 

1050 base_locals = dict(vars(base)) if localns is None else localns 1abgcdef

1051 if localns is None and globalns is None: 1abgcdef

1052 # This is surprising, but required. Before Python 3.10, 

1053 # get_type_hints only evaluated the globalns of 

1054 # a class. To maintain backwards compatibility, we reverse 

1055 # the globalns and localns order so that eval() looks into 

1056 # *base_globals* first rather than *base_locals*. 

1057 # This only affects ForwardRefs. 

1058 base_globals, base_locals = base_locals, base_globals 1abgcdef

1059 for name, value in ann.items(): 1abgcdef

1060 if value is None: 1abgcdef

1061 value = type(None) 

1062 if isinstance(value, str): 1abgcdef

1063 value = _make_forward_ref(value, is_argument=False, is_class=True) 1abgcdef

1064 

1065 value = eval_type_backport(value, base_globals, base_locals) 1abgcdef

1066 hints[name] = value 1abgcdef

1067 if not include_extras and hasattr(typing, '_strip_annotations'): 1abgcdef

1068 return { 1abgcdef

1069 k: typing._strip_annotations(t) # type: ignore 1abgcdef

1070 for k, t in hints.items() 1abgcdef

1071 } 

1072 else: 

1073 return hints 

1074 

1075 if globalns is None: 1abgcdef

1076 if isinstance(obj, types.ModuleType): 1abgcdef

1077 globalns = obj.__dict__ 

1078 else: 

1079 nsobj = obj 1abgcdef

1080 # Find globalns for the unwrapped object. 

1081 while hasattr(nsobj, '__wrapped__'): 1abgcdef

1082 nsobj = nsobj.__wrapped__ 

1083 globalns = getattr(nsobj, '__globals__', {}) 1abgcdef

1084 if localns is None: 1abgcdef

1085 localns = globalns 1abgcdef

1086 elif localns is None: 

1087 localns = globalns 

1088 hints = getattr(obj, '__annotations__', None) 1abgcdef

1089 if hints is None: 1abgcdef

1090 # Return empty annotations for something that _could_ have them. 

1091 if isinstance(obj, typing._allowed_types): # type: ignore 

1092 return {} 

1093 else: 

1094 raise TypeError(f'{obj!r} is not a module, class, method, or function.') 

1095 defaults = typing._get_defaults(obj) # type: ignore 1abgcdef

1096 hints = dict(hints) 1abgcdef

1097 for name, value in hints.items(): 1abgcdef

1098 if value is None: 1abgcdef

1099 value = type(None) 

1100 if isinstance(value, str): 1abgcdef

1101 # class-level forward refs were handled above, this must be either 

1102 # a module-level annotation or a function argument annotation 

1103 

1104 value = _make_forward_ref( 1abgcdef

1105 value, 1abgcdef

1106 is_argument=not isinstance(obj, types.ModuleType), 1abgcdef

1107 is_class=False, 1abgcdef

1108 ) 

1109 value = eval_type_backport(value, globalns, localns) 1abgcdef

1110 if name in defaults and defaults[name] is None: 1abgcdef

1111 value = typing.Optional[value] 

1112 hints[name] = value 1abgcdef

1113 return hints if include_extras else {k: typing._strip_annotations(t) for k, t in hints.items()} # type: ignore 1abgcdef