haiway 0.10.14__py3-none-any.whl → 0.10.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- haiway/__init__.py +111 -0
- haiway/context/__init__.py +27 -0
- haiway/context/access.py +615 -0
- haiway/context/disposables.py +78 -0
- haiway/context/identifier.py +92 -0
- haiway/context/logging.py +176 -0
- haiway/context/metrics.py +165 -0
- haiway/context/state.py +113 -0
- haiway/context/tasks.py +64 -0
- haiway/context/types.py +12 -0
- haiway/helpers/__init__.py +21 -0
- haiway/helpers/asynchrony.py +225 -0
- haiway/helpers/caching.py +326 -0
- haiway/helpers/metrics.py +459 -0
- haiway/helpers/retries.py +223 -0
- haiway/helpers/throttling.py +133 -0
- haiway/helpers/timeouted.py +112 -0
- haiway/helpers/tracing.py +137 -0
- haiway/py.typed +0 -0
- haiway/state/__init__.py +12 -0
- haiway/state/attributes.py +747 -0
- haiway/state/path.py +524 -0
- haiway/state/requirement.py +229 -0
- haiway/state/structure.py +414 -0
- haiway/state/validation.py +468 -0
- haiway/types/__init__.py +14 -0
- haiway/types/default.py +108 -0
- haiway/types/frozen.py +5 -0
- haiway/types/missing.py +95 -0
- haiway/utils/__init__.py +28 -0
- haiway/utils/always.py +61 -0
- haiway/utils/collections.py +185 -0
- haiway/utils/env.py +230 -0
- haiway/utils/freezing.py +28 -0
- haiway/utils/logs.py +57 -0
- haiway/utils/mimic.py +77 -0
- haiway/utils/noop.py +24 -0
- haiway/utils/queue.py +82 -0
- {haiway-0.10.14.dist-info → haiway-0.10.16.dist-info}/METADATA +1 -1
- haiway-0.10.16.dist-info/RECORD +42 -0
- haiway-0.10.14.dist-info/RECORD +0 -4
- {haiway-0.10.14.dist-info → haiway-0.10.16.dist-info}/WHEEL +0 -0
- {haiway-0.10.14.dist-info → haiway-0.10.16.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,747 @@
|
|
1
|
+
import types
|
2
|
+
import typing
|
3
|
+
from collections.abc import Callable, Mapping, MutableMapping, Sequence
|
4
|
+
from types import GenericAlias, NoneType, UnionType
|
5
|
+
from typing import (
|
6
|
+
Any,
|
7
|
+
ClassVar,
|
8
|
+
ForwardRef,
|
9
|
+
Generic,
|
10
|
+
Literal,
|
11
|
+
ParamSpec,
|
12
|
+
Self,
|
13
|
+
TypeAliasType,
|
14
|
+
TypeVar,
|
15
|
+
TypeVarTuple,
|
16
|
+
_GenericAlias, # pyright: ignore
|
17
|
+
get_args,
|
18
|
+
get_origin,
|
19
|
+
get_type_hints,
|
20
|
+
is_typeddict,
|
21
|
+
overload,
|
22
|
+
)
|
23
|
+
|
24
|
+
from haiway import types as haiway_types
|
25
|
+
from haiway.types import MISSING, Missing
|
26
|
+
|
27
|
+
__all__ = [
|
28
|
+
"AttributeAnnotation",
|
29
|
+
"attribute_annotations",
|
30
|
+
"resolve_attribute_annotation",
|
31
|
+
]
|
32
|
+
|
33
|
+
|
34
|
+
class AttributeAnnotation:
|
35
|
+
def __init__(
|
36
|
+
self,
|
37
|
+
*,
|
38
|
+
origin: Any,
|
39
|
+
arguments: Sequence[Any] | None = None,
|
40
|
+
required: bool = True,
|
41
|
+
extra: Mapping[str, Any] | None = None,
|
42
|
+
) -> None:
|
43
|
+
self.origin: Any = origin
|
44
|
+
self.arguments: Sequence[Any]
|
45
|
+
if arguments is None:
|
46
|
+
self.arguments = ()
|
47
|
+
|
48
|
+
else:
|
49
|
+
self.arguments = arguments
|
50
|
+
|
51
|
+
self.required: bool = required
|
52
|
+
self.extra: Mapping[str, Any]
|
53
|
+
if extra is None:
|
54
|
+
self.extra = {}
|
55
|
+
|
56
|
+
else:
|
57
|
+
self.extra = extra
|
58
|
+
|
59
|
+
def update_required(
|
60
|
+
self,
|
61
|
+
required: bool,
|
62
|
+
/,
|
63
|
+
) -> Self:
|
64
|
+
self.required = self.required and required
|
65
|
+
|
66
|
+
return self
|
67
|
+
|
68
|
+
def __str__(self) -> str:
|
69
|
+
if alias := self.extra.get("TYPE_ALIAS"):
|
70
|
+
return alias
|
71
|
+
|
72
|
+
origin_str: str = getattr(self.origin, "__name__", str(self.origin))
|
73
|
+
arguments_str: str
|
74
|
+
if self.arguments:
|
75
|
+
arguments_str = "[" + ", ".join(str(arg) for arg in self.arguments) + "]"
|
76
|
+
|
77
|
+
else:
|
78
|
+
arguments_str = ""
|
79
|
+
|
80
|
+
if module := getattr(self.origin, "__module__", None):
|
81
|
+
return f"{module}.{origin_str}{arguments_str}"
|
82
|
+
|
83
|
+
else:
|
84
|
+
return f"{origin_str}{arguments_str}"
|
85
|
+
|
86
|
+
|
87
|
+
def attribute_annotations(
|
88
|
+
cls: type[Any],
|
89
|
+
/,
|
90
|
+
type_parameters: Mapping[str, Any],
|
91
|
+
) -> Mapping[str, AttributeAnnotation]:
|
92
|
+
self_annotation = AttributeAnnotation(
|
93
|
+
origin=cls,
|
94
|
+
# ignore arguments here, State (and draive.DataModel) will have them resolved at this stage
|
95
|
+
arguments=[],
|
96
|
+
)
|
97
|
+
|
98
|
+
# ignore args_keys here, State (and draive.DataModel) will have them resolved at this stage
|
99
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation] = {
|
100
|
+
_recursion_key(cls, default=str(self_annotation)): self_annotation
|
101
|
+
}
|
102
|
+
|
103
|
+
attributes: dict[str, AttributeAnnotation] = {}
|
104
|
+
for key, annotation in get_type_hints(cls, localns={cls.__name__: cls}).items():
|
105
|
+
# do not include private or special items
|
106
|
+
if key.startswith("_"):
|
107
|
+
continue
|
108
|
+
|
109
|
+
# do not include ClassVars
|
110
|
+
if (get_origin(annotation) or annotation) is ClassVar:
|
111
|
+
continue
|
112
|
+
|
113
|
+
attributes[key] = resolve_attribute_annotation(
|
114
|
+
annotation,
|
115
|
+
type_parameters=type_parameters,
|
116
|
+
module=cls.__module__,
|
117
|
+
self_annotation=self_annotation,
|
118
|
+
recursion_guard=recursion_guard,
|
119
|
+
)
|
120
|
+
|
121
|
+
return attributes
|
122
|
+
|
123
|
+
|
124
|
+
def _resolve_none(
|
125
|
+
annotation: Any,
|
126
|
+
) -> AttributeAnnotation:
|
127
|
+
return AttributeAnnotation(origin=NoneType)
|
128
|
+
|
129
|
+
|
130
|
+
def _resolve_missing(
|
131
|
+
annotation: Any,
|
132
|
+
) -> AttributeAnnotation:
|
133
|
+
# special case - attributes marked as missing are not required
|
134
|
+
# Missing does not work properly within TypedDict though
|
135
|
+
return AttributeAnnotation(
|
136
|
+
origin=Missing,
|
137
|
+
required=False,
|
138
|
+
)
|
139
|
+
|
140
|
+
|
141
|
+
def _resolve_literal(
|
142
|
+
annotation: Any,
|
143
|
+
) -> AttributeAnnotation:
|
144
|
+
return AttributeAnnotation(
|
145
|
+
origin=Literal,
|
146
|
+
arguments=get_args(annotation),
|
147
|
+
)
|
148
|
+
|
149
|
+
|
150
|
+
def _resolve_forward_ref(
|
151
|
+
annotation: ForwardRef | str,
|
152
|
+
/,
|
153
|
+
module: str,
|
154
|
+
type_parameters: Mapping[str, Any],
|
155
|
+
self_annotation: AttributeAnnotation | None,
|
156
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
157
|
+
) -> AttributeAnnotation:
|
158
|
+
forward_ref: ForwardRef
|
159
|
+
match annotation:
|
160
|
+
case str() as string:
|
161
|
+
forward_ref = ForwardRef(string, module=module)
|
162
|
+
|
163
|
+
case reference:
|
164
|
+
forward_ref = reference
|
165
|
+
|
166
|
+
if evaluated := forward_ref._evaluate(
|
167
|
+
globalns=None,
|
168
|
+
localns=None,
|
169
|
+
recursive_guard=frozenset(),
|
170
|
+
):
|
171
|
+
return resolve_attribute_annotation(
|
172
|
+
evaluated,
|
173
|
+
type_parameters=type_parameters,
|
174
|
+
module=module,
|
175
|
+
self_annotation=self_annotation,
|
176
|
+
recursion_guard=recursion_guard,
|
177
|
+
)
|
178
|
+
|
179
|
+
else:
|
180
|
+
raise RuntimeError(f"Cannot resolve annotation of {annotation}")
|
181
|
+
|
182
|
+
|
183
|
+
def _resolve_generic_alias( # noqa: PLR0911, PLR0912
|
184
|
+
annotation: GenericAlias,
|
185
|
+
/,
|
186
|
+
module: str,
|
187
|
+
type_parameters: Mapping[str, Any],
|
188
|
+
self_annotation: AttributeAnnotation | None,
|
189
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
190
|
+
) -> AttributeAnnotation:
|
191
|
+
match get_origin(annotation):
|
192
|
+
case TypeAliasType() as alias: # pyright: ignore[reportUnnecessaryComparison]
|
193
|
+
return _resolve_type_alias(
|
194
|
+
alias,
|
195
|
+
type_parameters={
|
196
|
+
# verify if we should pass all parameters
|
197
|
+
param.__name__: get_args(annotation)[idx]
|
198
|
+
for idx, param in enumerate(alias.__type_params__)
|
199
|
+
},
|
200
|
+
module=module,
|
201
|
+
self_annotation=self_annotation,
|
202
|
+
recursion_guard=recursion_guard,
|
203
|
+
)
|
204
|
+
|
205
|
+
case origin if issubclass(origin, Generic):
|
206
|
+
match origin.__class_getitem__( # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
|
207
|
+
tuple(
|
208
|
+
type_parameters.get(
|
209
|
+
arg.__name__,
|
210
|
+
arg.__bound__ or Any,
|
211
|
+
)
|
212
|
+
if isinstance(arg, TypeVar)
|
213
|
+
else arg
|
214
|
+
for arg in get_args(annotation)
|
215
|
+
)
|
216
|
+
):
|
217
|
+
case GenericAlias() as generic_alias:
|
218
|
+
resolved_attribute = AttributeAnnotation(origin=generic_alias.__origin__)
|
219
|
+
if recursion_key := _recursion_key(generic_alias):
|
220
|
+
if recursive := recursion_guard.get(recursion_key):
|
221
|
+
return recursive
|
222
|
+
|
223
|
+
else:
|
224
|
+
recursion_guard[recursion_key] = resolved_attribute
|
225
|
+
|
226
|
+
resolved_attribute.arguments = [
|
227
|
+
resolve_attribute_annotation(
|
228
|
+
argument,
|
229
|
+
type_parameters=type_parameters,
|
230
|
+
module=module,
|
231
|
+
self_annotation=self_annotation,
|
232
|
+
recursion_guard=recursion_guard,
|
233
|
+
)
|
234
|
+
for argument in get_args(generic_alias)
|
235
|
+
]
|
236
|
+
|
237
|
+
return resolved_attribute
|
238
|
+
|
239
|
+
# use resolved type if it is not an alias again
|
240
|
+
case resolved: # pyright: ignore
|
241
|
+
resolved_attribute = AttributeAnnotation(origin=resolved)
|
242
|
+
|
243
|
+
if recursion_key := _recursion_key(origin):
|
244
|
+
if recursive := recursion_guard.get(recursion_key):
|
245
|
+
return recursive
|
246
|
+
|
247
|
+
else:
|
248
|
+
recursion_guard[recursion_key] = resolved_attribute
|
249
|
+
|
250
|
+
resolved_attribute.arguments = [
|
251
|
+
resolve_attribute_annotation(
|
252
|
+
argument,
|
253
|
+
type_parameters=type_parameters,
|
254
|
+
module=module,
|
255
|
+
self_annotation=self_annotation,
|
256
|
+
recursion_guard=recursion_guard,
|
257
|
+
)
|
258
|
+
for argument in get_args(annotation)
|
259
|
+
]
|
260
|
+
|
261
|
+
return resolved_attribute
|
262
|
+
|
263
|
+
case origin:
|
264
|
+
resolved_attribute = AttributeAnnotation(origin=origin)
|
265
|
+
|
266
|
+
if recursion_key := _recursion_key(origin):
|
267
|
+
if recursive := recursion_guard.get(recursion_key):
|
268
|
+
return recursive
|
269
|
+
|
270
|
+
resolved_attribute.arguments = [
|
271
|
+
resolve_attribute_annotation(
|
272
|
+
argument,
|
273
|
+
type_parameters=type_parameters,
|
274
|
+
module=module,
|
275
|
+
self_annotation=self_annotation,
|
276
|
+
recursion_guard=recursion_guard,
|
277
|
+
)
|
278
|
+
for argument in get_args(annotation)
|
279
|
+
]
|
280
|
+
|
281
|
+
return resolved_attribute
|
282
|
+
|
283
|
+
|
284
|
+
def _resolve_special_generic_alias(
|
285
|
+
annotation: Any,
|
286
|
+
/,
|
287
|
+
module: str,
|
288
|
+
type_parameters: Mapping[str, Any],
|
289
|
+
self_annotation: AttributeAnnotation | None,
|
290
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
291
|
+
) -> AttributeAnnotation:
|
292
|
+
origin: type[Any] = get_origin(annotation)
|
293
|
+
resolved_attribute = AttributeAnnotation(origin=origin)
|
294
|
+
|
295
|
+
if recursion_key := _recursion_key(origin):
|
296
|
+
if recursive := recursion_guard.get(recursion_key):
|
297
|
+
return recursive
|
298
|
+
|
299
|
+
else:
|
300
|
+
recursion_guard[recursion_key] = resolved_attribute
|
301
|
+
|
302
|
+
resolved_attribute.arguments = [
|
303
|
+
resolve_attribute_annotation(
|
304
|
+
argument,
|
305
|
+
type_parameters=type_parameters,
|
306
|
+
module=module,
|
307
|
+
self_annotation=self_annotation,
|
308
|
+
recursion_guard=recursion_guard,
|
309
|
+
)
|
310
|
+
for argument in get_args(annotation)
|
311
|
+
]
|
312
|
+
|
313
|
+
return resolved_attribute
|
314
|
+
|
315
|
+
|
316
|
+
def _resolve_type_alias(
|
317
|
+
annotation: TypeAliasType,
|
318
|
+
/,
|
319
|
+
module: str,
|
320
|
+
type_parameters: Mapping[str, Any],
|
321
|
+
self_annotation: AttributeAnnotation | None,
|
322
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
323
|
+
) -> AttributeAnnotation:
|
324
|
+
resolved_attribute = AttributeAnnotation(origin=MISSING)
|
325
|
+
|
326
|
+
if recursion_key := _recursion_key(annotation):
|
327
|
+
if recursive := recursion_guard.get(recursion_key):
|
328
|
+
return recursive
|
329
|
+
|
330
|
+
else:
|
331
|
+
recursion_guard[recursion_key] = resolved_attribute
|
332
|
+
|
333
|
+
resolved: AttributeAnnotation = resolve_attribute_annotation(
|
334
|
+
annotation.__value__,
|
335
|
+
module=annotation.__module__ or module,
|
336
|
+
type_parameters=type_parameters,
|
337
|
+
self_annotation=self_annotation,
|
338
|
+
recursion_guard=recursion_guard,
|
339
|
+
)
|
340
|
+
|
341
|
+
resolved_attribute.origin = resolved.origin
|
342
|
+
resolved_attribute.arguments = resolved.arguments
|
343
|
+
resolved_attribute.extra = {
|
344
|
+
**resolved.extra,
|
345
|
+
"TYPE_ALIAS": annotation.__name__,
|
346
|
+
}
|
347
|
+
resolved_attribute.required = resolved.required
|
348
|
+
|
349
|
+
return resolved_attribute
|
350
|
+
|
351
|
+
|
352
|
+
def _resolve_type_var(
|
353
|
+
annotation: TypeVar,
|
354
|
+
/,
|
355
|
+
module: str,
|
356
|
+
type_parameters: Mapping[str, Any],
|
357
|
+
self_annotation: AttributeAnnotation | None,
|
358
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
359
|
+
) -> AttributeAnnotation:
|
360
|
+
return resolve_attribute_annotation(
|
361
|
+
type_parameters.get(
|
362
|
+
annotation.__name__,
|
363
|
+
# use bound as default or Any otherwise
|
364
|
+
annotation.__bound__ or Any,
|
365
|
+
),
|
366
|
+
module=module,
|
367
|
+
type_parameters=type_parameters,
|
368
|
+
self_annotation=self_annotation,
|
369
|
+
recursion_guard=recursion_guard,
|
370
|
+
)
|
371
|
+
|
372
|
+
|
373
|
+
def _resolve_type_union(
|
374
|
+
annotation: UnionType,
|
375
|
+
/,
|
376
|
+
module: str,
|
377
|
+
type_parameters: Mapping[str, Any],
|
378
|
+
self_annotation: AttributeAnnotation | None,
|
379
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
380
|
+
) -> AttributeAnnotation:
|
381
|
+
arguments: Sequence[AttributeAnnotation] = [
|
382
|
+
resolve_attribute_annotation(
|
383
|
+
argument,
|
384
|
+
type_parameters=type_parameters,
|
385
|
+
module=module,
|
386
|
+
self_annotation=self_annotation,
|
387
|
+
recursion_guard=recursion_guard,
|
388
|
+
)
|
389
|
+
for argument in get_args(annotation)
|
390
|
+
]
|
391
|
+
return AttributeAnnotation(
|
392
|
+
origin=UnionType, # pyright: ignore[reportArgumentType]
|
393
|
+
arguments=arguments,
|
394
|
+
required=all(argument.required for argument in arguments),
|
395
|
+
)
|
396
|
+
|
397
|
+
|
398
|
+
def _resolve_callable(
|
399
|
+
annotation: Any,
|
400
|
+
/,
|
401
|
+
module: str,
|
402
|
+
type_parameters: Mapping[str, Any],
|
403
|
+
self_annotation: AttributeAnnotation | None,
|
404
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
405
|
+
) -> AttributeAnnotation:
|
406
|
+
return AttributeAnnotation(
|
407
|
+
origin=Callable,
|
408
|
+
arguments=[
|
409
|
+
resolve_attribute_annotation(
|
410
|
+
argument,
|
411
|
+
type_parameters=type_parameters,
|
412
|
+
module=module,
|
413
|
+
self_annotation=self_annotation,
|
414
|
+
recursion_guard=recursion_guard,
|
415
|
+
)
|
416
|
+
for argument in get_args(annotation)
|
417
|
+
],
|
418
|
+
)
|
419
|
+
|
420
|
+
|
421
|
+
def _resolve_type_box(
|
422
|
+
annotation: Any,
|
423
|
+
/,
|
424
|
+
module: str,
|
425
|
+
type_parameters: Mapping[str, Any],
|
426
|
+
self_annotation: AttributeAnnotation | None,
|
427
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
428
|
+
) -> AttributeAnnotation:
|
429
|
+
return resolve_attribute_annotation(
|
430
|
+
get_args(annotation)[0],
|
431
|
+
type_parameters=type_parameters,
|
432
|
+
module=module,
|
433
|
+
self_annotation=self_annotation,
|
434
|
+
recursion_guard=recursion_guard,
|
435
|
+
)
|
436
|
+
|
437
|
+
|
438
|
+
def _resolve_type_not_required(
|
439
|
+
annotation: Any,
|
440
|
+
/,
|
441
|
+
module: str,
|
442
|
+
type_parameters: Mapping[str, Any],
|
443
|
+
self_annotation: AttributeAnnotation | None,
|
444
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
445
|
+
) -> AttributeAnnotation:
|
446
|
+
return resolve_attribute_annotation(
|
447
|
+
get_args(annotation)[0],
|
448
|
+
type_parameters=type_parameters,
|
449
|
+
module=module,
|
450
|
+
self_annotation=self_annotation,
|
451
|
+
recursion_guard=recursion_guard,
|
452
|
+
).update_required(False)
|
453
|
+
|
454
|
+
|
455
|
+
def _resolve_type_optional(
|
456
|
+
annotation: Any,
|
457
|
+
/,
|
458
|
+
module: str,
|
459
|
+
type_parameters: Mapping[str, Any],
|
460
|
+
self_annotation: AttributeAnnotation | None,
|
461
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
462
|
+
) -> AttributeAnnotation:
|
463
|
+
return AttributeAnnotation(
|
464
|
+
origin=UnionType, # pyright: ignore[reportArgumentType]
|
465
|
+
arguments=[
|
466
|
+
resolve_attribute_annotation(
|
467
|
+
get_args(annotation)[0],
|
468
|
+
type_parameters=type_parameters,
|
469
|
+
module=module,
|
470
|
+
self_annotation=self_annotation,
|
471
|
+
recursion_guard=recursion_guard,
|
472
|
+
),
|
473
|
+
AttributeAnnotation(origin=NoneType),
|
474
|
+
],
|
475
|
+
)
|
476
|
+
|
477
|
+
|
478
|
+
def _resolve_type_typeddict(
|
479
|
+
annotation: Any,
|
480
|
+
/,
|
481
|
+
module: str,
|
482
|
+
type_parameters: Mapping[str, Any],
|
483
|
+
self_annotation: AttributeAnnotation | None,
|
484
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
485
|
+
) -> AttributeAnnotation:
|
486
|
+
resolved_attribute = AttributeAnnotation(origin=annotation)
|
487
|
+
|
488
|
+
if recursion_key := _recursion_key(annotation):
|
489
|
+
if recursive := recursion_guard.get(recursion_key):
|
490
|
+
return recursive
|
491
|
+
|
492
|
+
else:
|
493
|
+
recursion_guard[recursion_key] = resolved_attribute
|
494
|
+
|
495
|
+
resolved_attribute.arguments = [
|
496
|
+
resolve_attribute_annotation(
|
497
|
+
argument,
|
498
|
+
type_parameters=type_parameters,
|
499
|
+
module=module,
|
500
|
+
self_annotation=self_annotation,
|
501
|
+
recursion_guard=recursion_guard,
|
502
|
+
)
|
503
|
+
for argument in get_args(annotation)
|
504
|
+
]
|
505
|
+
|
506
|
+
attributes: dict[str, AttributeAnnotation] = {}
|
507
|
+
for key, element in get_type_hints(
|
508
|
+
annotation,
|
509
|
+
localns={annotation.__name__: annotation},
|
510
|
+
).items():
|
511
|
+
attributes[key] = resolve_attribute_annotation(
|
512
|
+
element,
|
513
|
+
type_parameters=type_parameters,
|
514
|
+
module=getattr(annotation, "__module__", module),
|
515
|
+
self_annotation=resolved_attribute,
|
516
|
+
recursion_guard=recursion_guard,
|
517
|
+
).update_required(key in annotation.__required_keys__)
|
518
|
+
resolved_attribute.extra = {
|
519
|
+
"attributes": attributes,
|
520
|
+
"required": annotation.__required_keys__,
|
521
|
+
}
|
522
|
+
return resolved_attribute
|
523
|
+
|
524
|
+
|
525
|
+
def _resolve_type(
|
526
|
+
annotation: Any,
|
527
|
+
/,
|
528
|
+
module: str,
|
529
|
+
type_parameters: Mapping[str, Any],
|
530
|
+
self_annotation: AttributeAnnotation | None,
|
531
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
532
|
+
) -> AttributeAnnotation:
|
533
|
+
if recursion_key := _recursion_key(annotation):
|
534
|
+
if recursive := recursion_guard.get(recursion_key):
|
535
|
+
return recursive
|
536
|
+
|
537
|
+
# not updating recursion guard here - it might be a builtin type
|
538
|
+
|
539
|
+
return AttributeAnnotation(
|
540
|
+
origin=annotation,
|
541
|
+
arguments=[
|
542
|
+
resolve_attribute_annotation(
|
543
|
+
argument,
|
544
|
+
type_parameters=type_parameters,
|
545
|
+
module=module,
|
546
|
+
self_annotation=self_annotation,
|
547
|
+
recursion_guard=recursion_guard,
|
548
|
+
)
|
549
|
+
for argument in get_args(annotation)
|
550
|
+
],
|
551
|
+
)
|
552
|
+
|
553
|
+
|
554
|
+
def resolve_attribute_annotation( # noqa: C901, PLR0911, PLR0912
|
555
|
+
annotation: Any,
|
556
|
+
/,
|
557
|
+
module: str,
|
558
|
+
type_parameters: Mapping[str, Any],
|
559
|
+
self_annotation: AttributeAnnotation | None,
|
560
|
+
recursion_guard: MutableMapping[str, AttributeAnnotation],
|
561
|
+
) -> AttributeAnnotation:
|
562
|
+
match get_origin(annotation) or annotation:
|
563
|
+
case types.NoneType | None:
|
564
|
+
return _resolve_none(
|
565
|
+
annotation=annotation,
|
566
|
+
)
|
567
|
+
|
568
|
+
case haiway_types.Missing:
|
569
|
+
return _resolve_missing(
|
570
|
+
annotation=annotation,
|
571
|
+
)
|
572
|
+
|
573
|
+
case types.UnionType | typing.Union:
|
574
|
+
return _resolve_type_union(
|
575
|
+
annotation,
|
576
|
+
module=module,
|
577
|
+
type_parameters=type_parameters,
|
578
|
+
self_annotation=self_annotation,
|
579
|
+
recursion_guard=recursion_guard,
|
580
|
+
)
|
581
|
+
|
582
|
+
case typing.Literal:
|
583
|
+
return _resolve_literal(annotation)
|
584
|
+
|
585
|
+
case typeddict if is_typeddict(typeddict):
|
586
|
+
return _resolve_type_typeddict(
|
587
|
+
typeddict,
|
588
|
+
module=module,
|
589
|
+
type_parameters=type_parameters,
|
590
|
+
self_annotation=self_annotation,
|
591
|
+
recursion_guard=recursion_guard,
|
592
|
+
)
|
593
|
+
|
594
|
+
case typing.Callable: # pyright: ignore
|
595
|
+
return _resolve_callable(
|
596
|
+
annotation,
|
597
|
+
module=module,
|
598
|
+
type_parameters=type_parameters,
|
599
|
+
self_annotation=self_annotation,
|
600
|
+
recursion_guard=recursion_guard,
|
601
|
+
)
|
602
|
+
|
603
|
+
case typing.Annotated | typing.Final | typing.Required:
|
604
|
+
return _resolve_type_box(
|
605
|
+
annotation,
|
606
|
+
module=module,
|
607
|
+
type_parameters=type_parameters,
|
608
|
+
self_annotation=self_annotation,
|
609
|
+
recursion_guard=recursion_guard,
|
610
|
+
)
|
611
|
+
|
612
|
+
case typing.NotRequired:
|
613
|
+
return _resolve_type_not_required(
|
614
|
+
annotation,
|
615
|
+
module=module,
|
616
|
+
type_parameters=type_parameters,
|
617
|
+
self_annotation=self_annotation,
|
618
|
+
recursion_guard=recursion_guard,
|
619
|
+
)
|
620
|
+
|
621
|
+
case typing.Optional: # optional is a Union[Value, None]
|
622
|
+
return _resolve_type_optional(
|
623
|
+
annotation,
|
624
|
+
module=module,
|
625
|
+
type_parameters=type_parameters,
|
626
|
+
self_annotation=self_annotation,
|
627
|
+
recursion_guard=recursion_guard,
|
628
|
+
)
|
629
|
+
|
630
|
+
case typing.Self: # pyright: ignore
|
631
|
+
if self_annotation:
|
632
|
+
return self_annotation
|
633
|
+
|
634
|
+
else:
|
635
|
+
raise RuntimeError(f"Unresolved Self annotation: {annotation}")
|
636
|
+
|
637
|
+
case _:
|
638
|
+
match annotation:
|
639
|
+
case str() | ForwardRef():
|
640
|
+
return _resolve_forward_ref(
|
641
|
+
annotation,
|
642
|
+
module=module,
|
643
|
+
type_parameters=type_parameters,
|
644
|
+
self_annotation=self_annotation,
|
645
|
+
recursion_guard=recursion_guard,
|
646
|
+
)
|
647
|
+
|
648
|
+
case GenericAlias():
|
649
|
+
return _resolve_generic_alias(
|
650
|
+
annotation,
|
651
|
+
module=module,
|
652
|
+
type_parameters=type_parameters,
|
653
|
+
self_annotation=self_annotation,
|
654
|
+
recursion_guard=recursion_guard,
|
655
|
+
)
|
656
|
+
|
657
|
+
case _GenericAlias():
|
658
|
+
return _resolve_special_generic_alias(
|
659
|
+
annotation,
|
660
|
+
module=module,
|
661
|
+
type_parameters=type_parameters,
|
662
|
+
self_annotation=self_annotation,
|
663
|
+
recursion_guard=recursion_guard,
|
664
|
+
)
|
665
|
+
|
666
|
+
case TypeAliasType():
|
667
|
+
return _resolve_type_alias(
|
668
|
+
annotation,
|
669
|
+
module=module,
|
670
|
+
type_parameters=type_parameters,
|
671
|
+
self_annotation=self_annotation,
|
672
|
+
recursion_guard=recursion_guard,
|
673
|
+
)
|
674
|
+
|
675
|
+
case TypeVar():
|
676
|
+
return _resolve_type_var(
|
677
|
+
annotation,
|
678
|
+
module=module,
|
679
|
+
type_parameters=type_parameters,
|
680
|
+
self_annotation=self_annotation,
|
681
|
+
recursion_guard=recursion_guard,
|
682
|
+
)
|
683
|
+
|
684
|
+
case ParamSpec():
|
685
|
+
raise NotImplementedError(f"Unresolved ParamSpec annotation: {annotation}")
|
686
|
+
|
687
|
+
case TypeVarTuple():
|
688
|
+
raise NotImplementedError(f"Unresolved TypeVarTuple annotation: {annotation}")
|
689
|
+
|
690
|
+
case _: # finally use whatever there was
|
691
|
+
return _resolve_type(
|
692
|
+
annotation,
|
693
|
+
module=module,
|
694
|
+
type_parameters=type_parameters,
|
695
|
+
self_annotation=self_annotation,
|
696
|
+
recursion_guard=recursion_guard,
|
697
|
+
)
|
698
|
+
|
699
|
+
|
700
|
+
@overload
|
701
|
+
def _recursion_key(
|
702
|
+
annotation: Any,
|
703
|
+
/,
|
704
|
+
) -> str | None: ...
|
705
|
+
|
706
|
+
|
707
|
+
@overload
|
708
|
+
def _recursion_key(
|
709
|
+
annotation: Any,
|
710
|
+
/,
|
711
|
+
default: str,
|
712
|
+
) -> str: ...
|
713
|
+
|
714
|
+
|
715
|
+
def _recursion_key(
|
716
|
+
annotation: Any,
|
717
|
+
/,
|
718
|
+
default: str | None = None,
|
719
|
+
) -> str | None:
|
720
|
+
args_suffix: str
|
721
|
+
if arguments := get_args(annotation):
|
722
|
+
arguments_string: str = ", ".join(
|
723
|
+
_recursion_key(
|
724
|
+
argument,
|
725
|
+
default="?",
|
726
|
+
)
|
727
|
+
for argument in arguments
|
728
|
+
)
|
729
|
+
args_suffix = f"[{arguments_string}]"
|
730
|
+
|
731
|
+
else:
|
732
|
+
args_suffix = ""
|
733
|
+
|
734
|
+
if qualname := getattr(annotation, "__qualname__", None):
|
735
|
+
return qualname + args_suffix
|
736
|
+
|
737
|
+
module_prefix: str
|
738
|
+
if module := getattr(annotation, "__module__", None):
|
739
|
+
module_prefix = module + "."
|
740
|
+
|
741
|
+
else:
|
742
|
+
module_prefix = ""
|
743
|
+
|
744
|
+
if name := getattr(annotation, "__name__", None):
|
745
|
+
return module_prefix + name + args_suffix
|
746
|
+
|
747
|
+
return default
|