haiway 0.10.15__py3-none-any.whl → 0.10.17__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 +542 -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.15.dist-info → haiway-0.10.17.dist-info}/METADATA +1 -1
- haiway-0.10.17.dist-info/RECORD +42 -0
- haiway-0.10.15.dist-info/RECORD +0 -4
- {haiway-0.10.15.dist-info → haiway-0.10.17.dist-info}/WHEEL +0 -0
- {haiway-0.10.15.dist-info → haiway-0.10.17.dist-info}/licenses/LICENSE +0 -0
haiway/state/path.py
ADDED
@@ -0,0 +1,542 @@
|
|
1
|
+
import builtins
|
2
|
+
import types
|
3
|
+
import typing
|
4
|
+
from abc import ABC, abstractmethod
|
5
|
+
from collections import abc as collections_abc
|
6
|
+
from collections import deque
|
7
|
+
from collections.abc import Callable, Mapping, Sequence
|
8
|
+
from copy import copy
|
9
|
+
from typing import Any, TypeAliasType, final, get_args, get_origin, overload
|
10
|
+
|
11
|
+
from haiway.types import MISSING, Missing, not_missing
|
12
|
+
|
13
|
+
__all__ = [
|
14
|
+
"AttributePath",
|
15
|
+
]
|
16
|
+
|
17
|
+
|
18
|
+
class AttributePathComponent(ABC):
|
19
|
+
@abstractmethod
|
20
|
+
def path_str(
|
21
|
+
self,
|
22
|
+
current: str | None = None,
|
23
|
+
/,
|
24
|
+
) -> str: ...
|
25
|
+
|
26
|
+
@abstractmethod
|
27
|
+
def access(
|
28
|
+
self,
|
29
|
+
subject: Any,
|
30
|
+
/,
|
31
|
+
) -> Any: ...
|
32
|
+
|
33
|
+
@abstractmethod
|
34
|
+
def assigning(
|
35
|
+
self,
|
36
|
+
subject: Any,
|
37
|
+
/,
|
38
|
+
value: Any,
|
39
|
+
) -> Any: ...
|
40
|
+
|
41
|
+
|
42
|
+
@final
|
43
|
+
class PropertyAttributePathComponent(AttributePathComponent):
|
44
|
+
def __init__[Root, Attribute](
|
45
|
+
self,
|
46
|
+
root: type[Root],
|
47
|
+
*,
|
48
|
+
attribute: type[Attribute],
|
49
|
+
name: str,
|
50
|
+
) -> None:
|
51
|
+
root_origin: Any = _unaliased_origin(root)
|
52
|
+
attribute_origin: Any = _unaliased_origin(attribute)
|
53
|
+
|
54
|
+
def access(
|
55
|
+
subject: Root,
|
56
|
+
/,
|
57
|
+
) -> Attribute:
|
58
|
+
assert isinstance(subject, root_origin), ( # nosec: B101
|
59
|
+
f"AttributePath used on unexpected subject of"
|
60
|
+
f" '{type(subject).__name__}' instead of '{root.__name__}' for '{name}'"
|
61
|
+
)
|
62
|
+
|
63
|
+
assert hasattr(subject, name), ( # nosec: B101
|
64
|
+
f"AttributePath pointing to attribute '{name}'"
|
65
|
+
f" which is not available in subject '{type(subject).__name__}'"
|
66
|
+
)
|
67
|
+
|
68
|
+
resolved: Any = getattr(subject, name)
|
69
|
+
|
70
|
+
assert isinstance(resolved, attribute_origin), ( # nosec: B101
|
71
|
+
f"AttributePath pointing to unexpected value of"
|
72
|
+
f" '{type(resolved).__name__}' instead of '{attribute.__name__}' for '{name}'"
|
73
|
+
)
|
74
|
+
return resolved
|
75
|
+
|
76
|
+
def assigning(
|
77
|
+
subject: Root,
|
78
|
+
/,
|
79
|
+
value: Attribute,
|
80
|
+
) -> Root:
|
81
|
+
assert isinstance(subject, root_origin), ( # nosec: B101
|
82
|
+
f"AttributePath used on unexpected subject of"
|
83
|
+
f" '{type(subject).__name__}' instead of '{root.__name__}' for '{name}'"
|
84
|
+
)
|
85
|
+
|
86
|
+
assert hasattr(subject, name), ( # nosec: B101
|
87
|
+
f"AttributePath pointing to attribute '{name}'"
|
88
|
+
f" which is not available in subject '{type(subject).__name__}'"
|
89
|
+
)
|
90
|
+
|
91
|
+
assert isinstance(value, attribute_origin), ( # nosec: B101
|
92
|
+
f"AttributePath assigning unexpected value of "
|
93
|
+
f"'{type(value).__name__}' instead of '{attribute.__name__}' for '{name}'"
|
94
|
+
)
|
95
|
+
|
96
|
+
updated: Root
|
97
|
+
# python 3.13 introduces __replace__, we are already implementing it for our types
|
98
|
+
if hasattr(subject, "__replace__"): # can't check full type here
|
99
|
+
updated = subject.__replace__(**{name: value}) # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType, reportAttributeAccessIssue]
|
100
|
+
|
101
|
+
else:
|
102
|
+
updated = copy(subject)
|
103
|
+
setattr(updated, name, value)
|
104
|
+
|
105
|
+
return updated # pyright: ignore[reportUnknownVariableType]
|
106
|
+
|
107
|
+
self._access: Callable[[Any], Any] = access
|
108
|
+
self._assigning: Callable[[Any, Any], Any] = assigning
|
109
|
+
self._name: str = name
|
110
|
+
|
111
|
+
def path_str(
|
112
|
+
self,
|
113
|
+
current: str | None = None,
|
114
|
+
/,
|
115
|
+
) -> str:
|
116
|
+
if current:
|
117
|
+
return f"{current}.{self._name}"
|
118
|
+
|
119
|
+
else:
|
120
|
+
return self._name
|
121
|
+
|
122
|
+
def access(
|
123
|
+
self,
|
124
|
+
subject: Any,
|
125
|
+
/,
|
126
|
+
) -> Any:
|
127
|
+
return self._access(subject)
|
128
|
+
|
129
|
+
def assigning(
|
130
|
+
self,
|
131
|
+
subject: Any,
|
132
|
+
/,
|
133
|
+
value: Any,
|
134
|
+
) -> Any:
|
135
|
+
return self._assigning(subject, value)
|
136
|
+
|
137
|
+
|
138
|
+
@final
|
139
|
+
class SequenceItemAttributePathComponent(AttributePathComponent):
|
140
|
+
def __init__[Root: Sequence[Any], Attribute](
|
141
|
+
self,
|
142
|
+
root: type[Root],
|
143
|
+
*,
|
144
|
+
attribute: type[Attribute],
|
145
|
+
index: int,
|
146
|
+
) -> None:
|
147
|
+
root_origin: Any = _unaliased_origin(root)
|
148
|
+
attribute_origin: Any = _unaliased_origin(attribute)
|
149
|
+
|
150
|
+
def access(
|
151
|
+
subject: Root,
|
152
|
+
/,
|
153
|
+
) -> Attribute:
|
154
|
+
assert isinstance(subject, root_origin), ( # nosec: B101
|
155
|
+
f"AttributePathComponent used on unexpected root of "
|
156
|
+
f"'{type(root).__name__}' instead of '{root.__name__}' for '{index}'"
|
157
|
+
)
|
158
|
+
|
159
|
+
resolved: Any = subject.__getitem__(index) # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
|
160
|
+
|
161
|
+
assert isinstance(resolved, attribute_origin), ( # nosec: B101
|
162
|
+
f"AttributePath pointing to unexpected value of "
|
163
|
+
f"'{type(resolved).__name__}' instead of '{attribute.__name__}' for '{index}'"
|
164
|
+
)
|
165
|
+
return resolved
|
166
|
+
|
167
|
+
def assigning(
|
168
|
+
subject: Root,
|
169
|
+
/,
|
170
|
+
value: Attribute,
|
171
|
+
) -> Root:
|
172
|
+
assert isinstance(subject, root_origin), ( # nosec: B101
|
173
|
+
f"AttributePath used on unexpected root of "
|
174
|
+
f"'{type(subject).__name__}' instead of '{root.__name__}' for '{index}'"
|
175
|
+
)
|
176
|
+
assert isinstance(value, attribute_origin), ( # nosec: B101
|
177
|
+
f"AttributePath assigning to unexpected value of "
|
178
|
+
f"'{type(value).__name__}' instead of '{attribute.__name__}' for '{index}'"
|
179
|
+
)
|
180
|
+
|
181
|
+
temp_list: list[Any] = list(subject) # pyright: ignore[reportUnknownArgumentType]
|
182
|
+
temp_list[index] = value
|
183
|
+
return subject.__class__(temp_list) # pyright: ignore[reportCallIssue, reportUnknownVariableType, reportUnknownMemberType]
|
184
|
+
|
185
|
+
self._access: Callable[[Any], Any] = access
|
186
|
+
self._assigning: Callable[[Any, Any], Any] = assigning
|
187
|
+
self._index: Any = index
|
188
|
+
|
189
|
+
def path_str(
|
190
|
+
self,
|
191
|
+
current: str | None = None,
|
192
|
+
/,
|
193
|
+
) -> str:
|
194
|
+
return f"{current or ''}[{self._index}]"
|
195
|
+
|
196
|
+
def access(
|
197
|
+
self,
|
198
|
+
subject: Any,
|
199
|
+
/,
|
200
|
+
) -> Any:
|
201
|
+
return self._access(subject)
|
202
|
+
|
203
|
+
def assigning(
|
204
|
+
self,
|
205
|
+
subject: Any,
|
206
|
+
/,
|
207
|
+
value: Any,
|
208
|
+
) -> Any:
|
209
|
+
return self._assigning(subject, value)
|
210
|
+
|
211
|
+
|
212
|
+
@final
|
213
|
+
class MappingItemAttributePathComponent(AttributePathComponent):
|
214
|
+
def __init__[Root: Mapping[Any, Any], Attribute](
|
215
|
+
self,
|
216
|
+
root: type[Root],
|
217
|
+
*,
|
218
|
+
attribute: type[Attribute],
|
219
|
+
key: str | int,
|
220
|
+
) -> None:
|
221
|
+
root_origin: Any = _unaliased_origin(root)
|
222
|
+
attribute_origin: Any = _unaliased_origin(attribute)
|
223
|
+
|
224
|
+
def access(
|
225
|
+
subject: Root,
|
226
|
+
/,
|
227
|
+
) -> Attribute:
|
228
|
+
assert isinstance(subject, root_origin), ( # nosec: B101
|
229
|
+
f"AttributePathComponent used on unexpected root of "
|
230
|
+
f"'{type(root).__name__}' instead of '{root.__name__}' for '{key}'"
|
231
|
+
)
|
232
|
+
|
233
|
+
resolved: Any = subject.__getitem__(key) # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
|
234
|
+
|
235
|
+
assert isinstance(resolved, attribute_origin), ( # nosec: B101
|
236
|
+
f"AttributePath pointing to unexpected value of "
|
237
|
+
f"'{type(resolved).__name__}' instead of '{attribute.__name__}' for '{key}'"
|
238
|
+
)
|
239
|
+
return resolved
|
240
|
+
|
241
|
+
def assigning(
|
242
|
+
subject: Root,
|
243
|
+
/,
|
244
|
+
value: Attribute,
|
245
|
+
) -> Root:
|
246
|
+
assert isinstance(subject, root_origin), ( # nosec: B101
|
247
|
+
f"AttributePath used on unexpected root of "
|
248
|
+
f"'{type(subject).__name__}' instead of '{root.__name__}' for '{key}'"
|
249
|
+
)
|
250
|
+
assert isinstance(value, attribute_origin), ( # nosec: B101
|
251
|
+
f"AttributePath assigning to unexpected value of "
|
252
|
+
f"'{type(value).__name__}' instead of '{attribute.__name__}' for '{key}'"
|
253
|
+
)
|
254
|
+
|
255
|
+
temp_dict: dict[Any, Any] = dict(subject) # pyright: ignore[reportUnknownArgumentType]
|
256
|
+
temp_dict[key] = value
|
257
|
+
return subject.__class__(temp_dict) # pyright: ignore[reportCallIssue, reportUnknownVariableType, reportUnknownMemberType]
|
258
|
+
|
259
|
+
self._access: Callable[[Any], Any] = access
|
260
|
+
self._assigning: Callable[[Any, Any], Any] = assigning
|
261
|
+
self._key: Any = key
|
262
|
+
|
263
|
+
def path_str(
|
264
|
+
self,
|
265
|
+
current: str | None = None,
|
266
|
+
/,
|
267
|
+
) -> str:
|
268
|
+
return f"{current or ''}[{self._key}]"
|
269
|
+
|
270
|
+
def access(
|
271
|
+
self,
|
272
|
+
subject: Any,
|
273
|
+
/,
|
274
|
+
) -> Any:
|
275
|
+
return self._access(subject)
|
276
|
+
|
277
|
+
def assigning(
|
278
|
+
self,
|
279
|
+
subject: Any,
|
280
|
+
/,
|
281
|
+
value: Any,
|
282
|
+
) -> Any:
|
283
|
+
return self._assigning(subject, value)
|
284
|
+
|
285
|
+
|
286
|
+
@final
|
287
|
+
class AttributePath[Root, Attribute]:
|
288
|
+
@overload
|
289
|
+
def __init__(
|
290
|
+
self,
|
291
|
+
root: type[Root],
|
292
|
+
/,
|
293
|
+
*,
|
294
|
+
attribute: type[Root],
|
295
|
+
) -> None: ...
|
296
|
+
|
297
|
+
@overload
|
298
|
+
def __init__(
|
299
|
+
self,
|
300
|
+
root: type[Root],
|
301
|
+
/,
|
302
|
+
*components: AttributePathComponent,
|
303
|
+
attribute: type[Attribute],
|
304
|
+
) -> None: ...
|
305
|
+
|
306
|
+
def __init__(
|
307
|
+
self,
|
308
|
+
root: type[Root],
|
309
|
+
/,
|
310
|
+
*components: AttributePathComponent,
|
311
|
+
attribute: type[Attribute],
|
312
|
+
) -> None:
|
313
|
+
assert components or root == attribute # nosec: B101
|
314
|
+
self.__root__: type[Root] = root
|
315
|
+
self.__attribute__: type[Attribute] = attribute
|
316
|
+
self.__components__: tuple[AttributePathComponent, ...] = components
|
317
|
+
|
318
|
+
@property
|
319
|
+
def components(self) -> Sequence[str]:
|
320
|
+
return tuple(component.path_str() for component in self.__components__)
|
321
|
+
|
322
|
+
def __str__(self) -> str:
|
323
|
+
path: str = ""
|
324
|
+
for component in self.__components__:
|
325
|
+
path = component.path_str(path)
|
326
|
+
|
327
|
+
return path
|
328
|
+
|
329
|
+
def __repr__(self) -> str:
|
330
|
+
path: str = self.__root__.__name__
|
331
|
+
for component in self.__components__:
|
332
|
+
path = component.path_str(path)
|
333
|
+
|
334
|
+
return path
|
335
|
+
|
336
|
+
def __getattr__(
|
337
|
+
self,
|
338
|
+
name: str,
|
339
|
+
) -> Any:
|
340
|
+
try:
|
341
|
+
return object.__getattribute__(self, name)
|
342
|
+
|
343
|
+
except (AttributeError, KeyError):
|
344
|
+
pass # continue
|
345
|
+
|
346
|
+
assert not name.startswith( # nosec: B101
|
347
|
+
"_"
|
348
|
+
), f"Accessing private/special attribute paths ({name}) is forbidden"
|
349
|
+
|
350
|
+
try:
|
351
|
+
annotation: Any = self.__attribute__.__annotations__[name]
|
352
|
+
|
353
|
+
except Exception as exc:
|
354
|
+
raise AttributeError(
|
355
|
+
f"Failed to prepare AttributePath caused by inaccessible"
|
356
|
+
f" type annotation for '{name}' within '{self.__attribute__.__name__}'"
|
357
|
+
) from exc
|
358
|
+
|
359
|
+
return AttributePath[Root, Any](
|
360
|
+
self.__root__,
|
361
|
+
*(
|
362
|
+
*self.__components__,
|
363
|
+
PropertyAttributePathComponent(
|
364
|
+
root=self.__attribute__,
|
365
|
+
attribute=annotation,
|
366
|
+
name=name,
|
367
|
+
),
|
368
|
+
),
|
369
|
+
attribute=annotation,
|
370
|
+
)
|
371
|
+
|
372
|
+
def __getitem__(
|
373
|
+
self,
|
374
|
+
key: str | int,
|
375
|
+
) -> Any:
|
376
|
+
match _unaliased_origin(self.__attribute__):
|
377
|
+
case collections_abc.Mapping | typing.Mapping | builtins.dict:
|
378
|
+
match get_args(_unaliased(self.__attribute__)):
|
379
|
+
case (builtins.str | builtins.int, element_annotation):
|
380
|
+
return AttributePath[Root, Any](
|
381
|
+
self.__root__,
|
382
|
+
*(
|
383
|
+
*self.__components__,
|
384
|
+
MappingItemAttributePathComponent(
|
385
|
+
root=self.__attribute__, # pyright: ignore[reportArgumentType]
|
386
|
+
attribute=element_annotation,
|
387
|
+
key=key,
|
388
|
+
),
|
389
|
+
),
|
390
|
+
attribute=element_annotation,
|
391
|
+
)
|
392
|
+
|
393
|
+
case other:
|
394
|
+
raise TypeError(
|
395
|
+
"Unsupported Mapping type annotation",
|
396
|
+
self.__attribute__.__name__,
|
397
|
+
)
|
398
|
+
|
399
|
+
case builtins.tuple:
|
400
|
+
if not isinstance(key, int):
|
401
|
+
raise TypeError(
|
402
|
+
"Unsupported tuple type annotation",
|
403
|
+
self.__attribute__.__name__,
|
404
|
+
)
|
405
|
+
|
406
|
+
match get_args(_unaliased(self.__attribute__)):
|
407
|
+
case (element_annotation, builtins.Ellipsis | types.EllipsisType):
|
408
|
+
return AttributePath[Root, Any](
|
409
|
+
self.__root__,
|
410
|
+
*(
|
411
|
+
*self.__components__,
|
412
|
+
SequenceItemAttributePathComponent(
|
413
|
+
root=self.__attribute__, # pyright: ignore[reportArgumentType]
|
414
|
+
attribute=element_annotation,
|
415
|
+
index=key,
|
416
|
+
),
|
417
|
+
),
|
418
|
+
attribute=element_annotation,
|
419
|
+
)
|
420
|
+
|
421
|
+
case other:
|
422
|
+
return AttributePath[Root, Any](
|
423
|
+
self.__root__,
|
424
|
+
*(
|
425
|
+
*self.__components__,
|
426
|
+
SequenceItemAttributePathComponent(
|
427
|
+
root=self.__attribute__, # pyright: ignore[reportArgumentType]
|
428
|
+
attribute=other[key],
|
429
|
+
index=key,
|
430
|
+
),
|
431
|
+
),
|
432
|
+
attribute=other[key],
|
433
|
+
)
|
434
|
+
|
435
|
+
case collections_abc.Sequence | typing.Sequence | builtins.list:
|
436
|
+
if not isinstance(key, int):
|
437
|
+
raise TypeError(
|
438
|
+
"Unsupported Sequence type annotation",
|
439
|
+
self.__attribute__.__name__,
|
440
|
+
)
|
441
|
+
|
442
|
+
match get_args(_unaliased(self.__attribute__)):
|
443
|
+
case (element_annotation,):
|
444
|
+
return AttributePath[Root, Any](
|
445
|
+
self.__root__,
|
446
|
+
*(
|
447
|
+
*self.__components__,
|
448
|
+
SequenceItemAttributePathComponent(
|
449
|
+
root=self.__attribute__, # pyright: ignore[reportArgumentType]
|
450
|
+
attribute=element_annotation,
|
451
|
+
index=key,
|
452
|
+
),
|
453
|
+
),
|
454
|
+
attribute=element_annotation,
|
455
|
+
)
|
456
|
+
|
457
|
+
case other:
|
458
|
+
raise TypeError(
|
459
|
+
"Unsupported Seqence type annotation",
|
460
|
+
self.__attribute__.__name__,
|
461
|
+
)
|
462
|
+
|
463
|
+
case other:
|
464
|
+
raise TypeError("Unsupported type annotation", other)
|
465
|
+
|
466
|
+
@overload
|
467
|
+
def __call__(
|
468
|
+
self,
|
469
|
+
root: Root,
|
470
|
+
/,
|
471
|
+
) -> Attribute: ...
|
472
|
+
|
473
|
+
@overload
|
474
|
+
def __call__(
|
475
|
+
self,
|
476
|
+
root: Root,
|
477
|
+
/,
|
478
|
+
updated: Attribute,
|
479
|
+
) -> Root: ...
|
480
|
+
|
481
|
+
def __call__(
|
482
|
+
self,
|
483
|
+
root: Root,
|
484
|
+
/,
|
485
|
+
updated: Attribute | Missing = MISSING,
|
486
|
+
) -> Root | Attribute:
|
487
|
+
assert isinstance(root, _unaliased_origin(self.__root__)), ( # nosec: B101
|
488
|
+
f"AttributePath '{self.__repr__()}' used on unexpected root of "
|
489
|
+
f"'{type(root).__name__}' instead of '{self.__root__.__name__}'"
|
490
|
+
)
|
491
|
+
|
492
|
+
if not_missing(updated):
|
493
|
+
assert isinstance(updated, _unaliased_origin(self.__attribute__)), ( # nosec: B101
|
494
|
+
f"AttributePath '{self.__repr__()}' assigning to unexpected value of "
|
495
|
+
f"'{type(updated).__name__}' instead of '{self.__attribute__.__name__}'"
|
496
|
+
)
|
497
|
+
|
498
|
+
resolved: Any = root
|
499
|
+
updates_stack: deque[tuple[Any, AttributePathComponent]] = deque()
|
500
|
+
for component in self.__components__:
|
501
|
+
updates_stack.append((resolved, component))
|
502
|
+
resolved = component.access(resolved)
|
503
|
+
|
504
|
+
updated_value: Any = updated
|
505
|
+
while updates_stack:
|
506
|
+
subject, component = updates_stack.pop()
|
507
|
+
updated_value = component.assigning(
|
508
|
+
subject,
|
509
|
+
value=updated_value,
|
510
|
+
)
|
511
|
+
|
512
|
+
return updated_value
|
513
|
+
|
514
|
+
else:
|
515
|
+
resolved: Any = root
|
516
|
+
for component in self.__components__:
|
517
|
+
resolved = component.access(resolved)
|
518
|
+
|
519
|
+
assert isinstance(resolved, _unaliased_origin(self.__attribute__)), ( # nosec: B101
|
520
|
+
f"AttributePath '{self.__repr__()}' pointing to unexpected value of "
|
521
|
+
f"'{type(resolved).__name__}' instead of '{self.__attribute__.__name__}'"
|
522
|
+
)
|
523
|
+
|
524
|
+
return resolved
|
525
|
+
|
526
|
+
|
527
|
+
def _unaliased_origin(base: type[Any]) -> type[Any]:
|
528
|
+
match base:
|
529
|
+
case TypeAliasType() as aliased:
|
530
|
+
return get_origin(aliased.__value__) or aliased.__value__
|
531
|
+
|
532
|
+
case concrete:
|
533
|
+
return get_origin(concrete) or concrete
|
534
|
+
|
535
|
+
|
536
|
+
def _unaliased(base: type[Any]) -> type[Any]:
|
537
|
+
match base:
|
538
|
+
case TypeAliasType() as aliased:
|
539
|
+
return aliased.__value__
|
540
|
+
|
541
|
+
case concrete:
|
542
|
+
return concrete
|