haiway 0.11.1__py3-none-any.whl → 0.12.0__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/context/tasks.py CHANGED
@@ -1,8 +1,8 @@
1
1
  from asyncio import Task, TaskGroup, get_event_loop
2
2
  from collections.abc import Callable, Coroutine
3
- from contextvars import ContextVar, copy_context
3
+ from contextvars import ContextVar, Token, copy_context
4
4
  from types import TracebackType
5
- from typing import final
5
+ from typing import Any, final
6
6
 
7
7
  __all__ = [
8
8
  "TaskGroupContext",
@@ -33,15 +33,54 @@ class TaskGroupContext:
33
33
  context=copy_context(),
34
34
  )
35
35
 
36
+ __slots__ = (
37
+ "_group",
38
+ "_token",
39
+ )
40
+
36
41
  def __init__(
37
42
  self,
38
43
  ) -> None:
39
- self._group: TaskGroup = TaskGroup()
44
+ self._group: TaskGroup
45
+ object.__setattr__(
46
+ self,
47
+ "_group",
48
+ TaskGroup(),
49
+ )
50
+ self._token: Token[TaskGroup] | None
51
+ object.__setattr__(
52
+ self,
53
+ "_token",
54
+ None,
55
+ )
56
+
57
+ def __setattr__(
58
+ self,
59
+ name: str,
60
+ value: Any,
61
+ ) -> Any:
62
+ raise AttributeError(
63
+ f"Can't modify immutable {self.__class__.__qualname__},"
64
+ f" attribute - '{name}' cannot be modified"
65
+ )
66
+
67
+ def __delattr__(
68
+ self,
69
+ name: str,
70
+ ) -> None:
71
+ raise AttributeError(
72
+ f"Can't modify immutable {self.__class__.__qualname__},"
73
+ f" attribute - '{name}' cannot be deleted"
74
+ )
40
75
 
41
76
  async def __aenter__(self) -> None:
42
- assert not hasattr(self, "_token"), "Context reentrance is not allowed" # nosec: B101
77
+ assert self._token is None, "Context reentrance is not allowed" # nosec: B101
43
78
  await self._group.__aenter__()
44
- self._token = TaskGroupContext._context.set(self._group)
79
+ object.__setattr__(
80
+ self,
81
+ "_token",
82
+ TaskGroupContext._context.set(self._group),
83
+ )
45
84
 
46
85
  async def __aexit__(
47
86
  self,
@@ -49,9 +88,13 @@ class TaskGroupContext:
49
88
  exc_val: BaseException | None,
50
89
  exc_tb: TracebackType | None,
51
90
  ) -> None:
52
- assert hasattr(self, "_token"), "Unbalanced context enter/exit" # nosec: B101
91
+ assert self._token is not None, "Unbalanced context enter/exit" # nosec: B101
53
92
  TaskGroupContext._context.reset(self._token)
54
- del self._token
93
+ object.__setattr__(
94
+ self,
95
+ "_token",
96
+ None,
97
+ )
55
98
 
56
99
  try:
57
100
  await self._group.__aexit__(
@@ -107,6 +107,20 @@ def asynchronous[**Args, Result](
107
107
 
108
108
 
109
109
  class _ExecutorWrapper[**Args, Result]:
110
+ __slots__ = (
111
+ "__annotations__",
112
+ "__defaults__",
113
+ "__doc__",
114
+ "__globals__",
115
+ "__kwdefaults__",
116
+ "__name__",
117
+ "__qualname__",
118
+ "__wrapped__",
119
+ "_executor",
120
+ "_function",
121
+ "_loop",
122
+ )
123
+
110
124
  def __init__(
111
125
  self,
112
126
  function: Callable[Args, Result],
haiway/helpers/caching.py CHANGED
@@ -89,6 +89,21 @@ class _CacheEntry[Entry](NamedTuple):
89
89
 
90
90
 
91
91
  class _SyncCache[**Args, Result]:
92
+ __slots__ = (
93
+ "__annotations__",
94
+ "__defaults__",
95
+ "__doc__",
96
+ "__globals__",
97
+ "__kwdefaults__",
98
+ "__name__",
99
+ "__qualname__",
100
+ "__wrapped__",
101
+ "_cached",
102
+ "_function",
103
+ "_limit",
104
+ "_next_expire_time",
105
+ )
106
+
92
107
  def __init__(
93
108
  self,
94
109
  function: Callable[Args, Result],
@@ -206,6 +221,21 @@ class _SyncCache[**Args, Result]:
206
221
 
207
222
 
208
223
  class _AsyncCache[**Args, Result]:
224
+ __slots__ = (
225
+ "__annotations__",
226
+ "__defaults__",
227
+ "__doc__",
228
+ "__globals__",
229
+ "__kwdefaults__",
230
+ "__name__",
231
+ "__qualname__",
232
+ "__wrapped__",
233
+ "_cached",
234
+ "_function",
235
+ "_limit",
236
+ "_next_expire_time",
237
+ )
238
+
209
239
  def __init__(
210
240
  self,
211
241
  function: Callable[Args, Coroutine[None, None, Result]],
haiway/helpers/metrics.py CHANGED
@@ -14,6 +14,14 @@ __all_ = [
14
14
 
15
15
 
16
16
  class MetricsScopeStore:
17
+ __slots__ = (
18
+ "entered",
19
+ "exited",
20
+ "identifier",
21
+ "metrics",
22
+ "nested",
23
+ )
24
+
17
25
  def __init__(
18
26
  self,
19
27
  identifier: ScopeIdentifier,
@@ -100,6 +108,11 @@ class MetricsHolder:
100
108
  exit_scope=store_handler.exit_scope,
101
109
  )
102
110
 
111
+ __slots__ = (
112
+ "root_scope",
113
+ "scopes",
114
+ )
115
+
103
116
  def __init__(self) -> None:
104
117
  self.root_scope: ScopeIdentifier | None = None
105
118
  self.scopes: dict[ScopeIdentifier, MetricsScopeStore] = {}
@@ -187,6 +200,13 @@ class MetricsLogger:
187
200
  exit_scope=logger_handler.exit_scope,
188
201
  )
189
202
 
203
+ __slots__ = (
204
+ "items_limit",
205
+ "redact_content",
206
+ "root_scope",
207
+ "scopes",
208
+ )
209
+
190
210
  def __init__(
191
211
  self,
192
212
  items_limit: int | None,
@@ -89,6 +89,22 @@ def throttle[**Args, Result](
89
89
 
90
90
 
91
91
  class _AsyncThrottle[**Args, Result]:
92
+ __slots__ = (
93
+ "__annotations__",
94
+ "__defaults__",
95
+ "__doc__",
96
+ "__globals__",
97
+ "__kwdefaults__",
98
+ "__name__",
99
+ "__qualname__",
100
+ "__wrapped__",
101
+ "_entries",
102
+ "_function",
103
+ "_limit",
104
+ "_lock",
105
+ "_period",
106
+ )
107
+
92
108
  def __init__(
93
109
  self,
94
110
  function: Callable[Args, Coroutine[None, None, Result]],
@@ -45,6 +45,19 @@ def timeout[**Args, Result](
45
45
 
46
46
 
47
47
  class _AsyncTimeout[**Args, Result]:
48
+ __slots__ = (
49
+ "__annotations__",
50
+ "__defaults__",
51
+ "__doc__",
52
+ "__globals__",
53
+ "__kwdefaults__",
54
+ "__name__",
55
+ "__qualname__",
56
+ "__wrapped__",
57
+ "_function",
58
+ "_timeout",
59
+ )
60
+
48
61
  def __init__(
49
62
  self,
50
63
  function: Callable[Args, Coroutine[None, None, Result]],
@@ -14,6 +14,7 @@ from typing import (
14
14
  TypeVar,
15
15
  TypeVarTuple,
16
16
  _GenericAlias, # pyright: ignore
17
+ final,
17
18
  get_args,
18
19
  get_origin,
19
20
  get_type_hints,
@@ -31,7 +32,15 @@ __all__ = [
31
32
  ]
32
33
 
33
34
 
35
+ @final
34
36
  class AttributeAnnotation:
37
+ __slots__ = (
38
+ "arguments",
39
+ "extra",
40
+ "origin",
41
+ "required",
42
+ )
43
+
35
44
  def __init__(
36
45
  self,
37
46
  *,
@@ -49,6 +58,7 @@ class AttributeAnnotation:
49
58
  self.arguments = arguments
50
59
 
51
60
  self.required: bool = required
61
+
52
62
  self.extra: Mapping[str, Any]
53
63
  if extra is None:
54
64
  self.extra = {}
@@ -61,7 +71,11 @@ class AttributeAnnotation:
61
71
  required: bool,
62
72
  /,
63
73
  ) -> Self:
64
- self.required = self.required and required
74
+ object.__setattr__(
75
+ self,
76
+ "required",
77
+ self.required and required,
78
+ )
65
79
 
66
80
  return self
67
81
 
haiway/state/path.py CHANGED
@@ -41,6 +41,12 @@ class AttributePathComponent(ABC):
41
41
 
42
42
  @final
43
43
  class PropertyAttributePathComponent(AttributePathComponent):
44
+ __slots__ = (
45
+ "_access",
46
+ "_assigning",
47
+ "_name",
48
+ )
49
+
44
50
  def __init__[Root, Attribute](
45
51
  self,
46
52
  root: type[Root],
@@ -104,9 +110,43 @@ class PropertyAttributePathComponent(AttributePathComponent):
104
110
 
105
111
  return updated # pyright: ignore[reportUnknownVariableType]
106
112
 
107
- self._access: Callable[[Any], Any] = access
108
- self._assigning: Callable[[Any, Any], Any] = assigning
109
- self._name: str = name
113
+ self._access: Callable[[Any], Any]
114
+ object.__setattr__(
115
+ self,
116
+ "_access",
117
+ access,
118
+ )
119
+ self._assigning: Callable[[Any, Any], Any]
120
+ object.__setattr__(
121
+ self,
122
+ "_assigning",
123
+ assigning,
124
+ )
125
+ self._name: str
126
+ object.__setattr__(
127
+ self,
128
+ "_name",
129
+ name,
130
+ )
131
+
132
+ def __setattr__(
133
+ self,
134
+ name: str,
135
+ value: Any,
136
+ ) -> Any:
137
+ raise AttributeError(
138
+ f"Can't modify immutable {self.__class__.__qualname__},"
139
+ f" attribute - '{name}' cannot be modified"
140
+ )
141
+
142
+ def __delattr__(
143
+ self,
144
+ name: str,
145
+ ) -> None:
146
+ raise AttributeError(
147
+ f"Can't modify immutable {self.__class__.__qualname__},"
148
+ f" attribute - '{name}' cannot be deleted"
149
+ )
110
150
 
111
151
  def path_str(
112
152
  self,
@@ -137,6 +177,12 @@ class PropertyAttributePathComponent(AttributePathComponent):
137
177
 
138
178
  @final
139
179
  class SequenceItemAttributePathComponent(AttributePathComponent):
180
+ __slots__ = (
181
+ "_access",
182
+ "_assigning",
183
+ "_index",
184
+ )
185
+
140
186
  def __init__[Root: Sequence[Any], Attribute](
141
187
  self,
142
188
  root: type[Root],
@@ -182,9 +228,43 @@ class SequenceItemAttributePathComponent(AttributePathComponent):
182
228
  temp_list[index] = value
183
229
  return subject.__class__(temp_list) # pyright: ignore[reportCallIssue, reportUnknownVariableType, reportUnknownMemberType]
184
230
 
185
- self._access: Callable[[Any], Any] = access
186
- self._assigning: Callable[[Any, Any], Any] = assigning
187
- self._index: Any = index
231
+ self._access: Callable[[Any], Any]
232
+ object.__setattr__(
233
+ self,
234
+ "_access",
235
+ access,
236
+ )
237
+ self._assigning: Callable[[Any, Any], Any]
238
+ object.__setattr__(
239
+ self,
240
+ "_assigning",
241
+ assigning,
242
+ )
243
+ self._index: Any
244
+ object.__setattr__(
245
+ self,
246
+ "_index",
247
+ index,
248
+ )
249
+
250
+ def __setattr__(
251
+ self,
252
+ name: str,
253
+ value: Any,
254
+ ) -> Any:
255
+ raise AttributeError(
256
+ f"Can't modify immutable {self.__class__.__qualname__},"
257
+ f" attribute - '{name}' cannot be modified"
258
+ )
259
+
260
+ def __delattr__(
261
+ self,
262
+ name: str,
263
+ ) -> None:
264
+ raise AttributeError(
265
+ f"Can't modify immutable {self.__class__.__qualname__},"
266
+ f" attribute - '{name}' cannot be deleted"
267
+ )
188
268
 
189
269
  def path_str(
190
270
  self,
@@ -211,6 +291,12 @@ class SequenceItemAttributePathComponent(AttributePathComponent):
211
291
 
212
292
  @final
213
293
  class MappingItemAttributePathComponent(AttributePathComponent):
294
+ __slots__ = (
295
+ "_access",
296
+ "_assigning",
297
+ "_key",
298
+ )
299
+
214
300
  def __init__[Root: Mapping[Any, Any], Attribute](
215
301
  self,
216
302
  root: type[Root],
@@ -256,9 +342,43 @@ class MappingItemAttributePathComponent(AttributePathComponent):
256
342
  temp_dict[key] = value
257
343
  return subject.__class__(temp_dict) # pyright: ignore[reportCallIssue, reportUnknownVariableType, reportUnknownMemberType]
258
344
 
259
- self._access: Callable[[Any], Any] = access
260
- self._assigning: Callable[[Any, Any], Any] = assigning
261
- self._key: Any = key
345
+ self._access: Callable[[Any], Any]
346
+ object.__setattr__(
347
+ self,
348
+ "_access",
349
+ access,
350
+ )
351
+ self._assigning: Callable[[Any, Any], Any]
352
+ object.__setattr__(
353
+ self,
354
+ "_assigning",
355
+ assigning,
356
+ )
357
+ self._key: Any
358
+ object.__setattr__(
359
+ self,
360
+ "_key",
361
+ key,
362
+ )
363
+
364
+ def __setattr__(
365
+ self,
366
+ name: str,
367
+ value: Any,
368
+ ) -> Any:
369
+ raise AttributeError(
370
+ f"Can't modify immutable {self.__class__.__qualname__},"
371
+ f" attribute - '{name}' cannot be modified"
372
+ )
373
+
374
+ def __delattr__(
375
+ self,
376
+ name: str,
377
+ ) -> None:
378
+ raise AttributeError(
379
+ f"Can't modify immutable {self.__class__.__qualname__},"
380
+ f" attribute - '{name}' cannot be deleted"
381
+ )
262
382
 
263
383
  def path_str(
264
384
  self,
@@ -285,6 +405,12 @@ class MappingItemAttributePathComponent(AttributePathComponent):
285
405
 
286
406
  @final
287
407
  class AttributePath[Root, Attribute]:
408
+ __slots__ = (
409
+ "__attribute__",
410
+ "__components__",
411
+ "__root__",
412
+ )
413
+
288
414
  @overload
289
415
  def __init__(
290
416
  self,
@@ -311,9 +437,43 @@ class AttributePath[Root, Attribute]:
311
437
  attribute: type[Attribute],
312
438
  ) -> None:
313
439
  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
440
+ self.__root__: type[Root]
441
+ object.__setattr__(
442
+ self,
443
+ "__root__",
444
+ root,
445
+ )
446
+ self.__attribute__: type[Attribute]
447
+ object.__setattr__(
448
+ self,
449
+ "__attribute__",
450
+ attribute,
451
+ )
452
+ self.__components__: tuple[AttributePathComponent, ...]
453
+ object.__setattr__(
454
+ self,
455
+ "__components__",
456
+ components,
457
+ )
458
+
459
+ def __setattr__(
460
+ self,
461
+ name: str,
462
+ value: Any,
463
+ ) -> Any:
464
+ raise AttributeError(
465
+ f"Can't modify immutable {self.__class__.__qualname__},"
466
+ f" attribute - '{name}' cannot be modified"
467
+ )
468
+
469
+ def __delattr__(
470
+ self,
471
+ name: str,
472
+ ) -> None:
473
+ raise AttributeError(
474
+ f"Can't modify immutable {self.__class__.__qualname__},"
475
+ f" attribute - '{name}' cannot be deleted"
476
+ )
317
477
 
318
478
  @property
319
479
  def components(self) -> Sequence[str]:
@@ -2,7 +2,6 @@ from collections.abc import Callable, Collection, Iterable
2
2
  from typing import Any, Literal, Self, cast, final
3
3
 
4
4
  from haiway.state.path import AttributePath
5
- from haiway.utils import freeze
6
5
 
7
6
  __all__ = [
8
7
  "AttributeRequirement",
@@ -142,6 +141,13 @@ class AttributeRequirement[Root]:
142
141
  check=check_contained_in,
143
142
  )
144
143
 
144
+ __slots__ = (
145
+ "_check",
146
+ "lhs",
147
+ "operator",
148
+ "rhs",
149
+ )
150
+
145
151
  def __init__(
146
152
  self,
147
153
  lhs: Any,
@@ -157,7 +163,12 @@ class AttributeRequirement[Root]:
157
163
  rhs: Any,
158
164
  check: Callable[[Root], None],
159
165
  ) -> None:
160
- self.lhs: Any = lhs
166
+ self.lhs: Any
167
+ object.__setattr__(
168
+ self,
169
+ "lhs",
170
+ lhs,
171
+ )
161
172
  self.operator: Literal[
162
173
  "equal",
163
174
  "not_equal",
@@ -166,11 +177,24 @@ class AttributeRequirement[Root]:
166
177
  "contained_in",
167
178
  "and",
168
179
  "or",
169
- ] = operator
170
- self.rhs: Any = rhs
171
- self._check: Callable[[Root], None] = check
172
-
173
- freeze(self)
180
+ ]
181
+ object.__setattr__(
182
+ self,
183
+ "operator",
184
+ operator,
185
+ )
186
+ self.rhs: Any
187
+ object.__setattr__(
188
+ self,
189
+ "rhs",
190
+ rhs,
191
+ )
192
+ self._check: Callable[[Root], None]
193
+ object.__setattr__(
194
+ self,
195
+ "_check",
196
+ check,
197
+ )
174
198
 
175
199
  def __and__(
176
200
  self,
@@ -227,3 +251,22 @@ class AttributeRequirement[Root]:
227
251
  values: Iterable[Root],
228
252
  ) -> list[Root]:
229
253
  return [value for value in values if self.check(value, raise_exception=False)]
254
+
255
+ def __setattr__(
256
+ self,
257
+ name: str,
258
+ value: Any,
259
+ ) -> Any:
260
+ raise AttributeError(
261
+ f"Can't modify immutable {self.__class__.__qualname__},"
262
+ f" attribute - '{name}' cannot be modified"
263
+ )
264
+
265
+ def __delattr__(
266
+ self,
267
+ name: str,
268
+ ) -> None:
269
+ raise AttributeError(
270
+ f"Can't modify immutable {self.__class__.__qualname__},"
271
+ f" attribute - '{name}' cannot be deleted"
272
+ )
haiway/state/structure.py CHANGED
@@ -49,6 +49,13 @@ def Default[Value](
49
49
 
50
50
  @final
51
51
  class StateAttribute[Value]:
52
+ __slots__ = (
53
+ "annotation",
54
+ "default",
55
+ "name",
56
+ "validator",
57
+ )
58
+
52
59
  def __init__(
53
60
  self,
54
61
  name: str,
@@ -56,10 +63,30 @@ class StateAttribute[Value]:
56
63
  default: DefaultValue[Value],
57
64
  validator: AttributeValidation[Value],
58
65
  ) -> None:
59
- self.name: str = name
60
- self.annotation: AttributeAnnotation = annotation
61
- self.default: DefaultValue[Value] = default
62
- self.validator: AttributeValidation[Value] = validator
66
+ self.name: str
67
+ object.__setattr__(
68
+ self,
69
+ "name",
70
+ name,
71
+ )
72
+ self.annotation: AttributeAnnotation
73
+ object.__setattr__(
74
+ self,
75
+ "annotation",
76
+ annotation,
77
+ )
78
+ self.default: DefaultValue[Value]
79
+ object.__setattr__(
80
+ self,
81
+ "default",
82
+ default,
83
+ )
84
+ self.validator: AttributeValidation[Value]
85
+ object.__setattr__(
86
+ self,
87
+ "validator",
88
+ validator,
89
+ )
63
90
 
64
91
  def validated(
65
92
  self,
@@ -68,6 +95,25 @@ class StateAttribute[Value]:
68
95
  ) -> Value:
69
96
  return self.validator(self.default() if value is MISSING else value)
70
97
 
98
+ def __setattr__(
99
+ self,
100
+ name: str,
101
+ value: Any,
102
+ ) -> Any:
103
+ raise AttributeError(
104
+ f"Can't modify immutable {self.__class__.__qualname__},"
105
+ f" attribute - '{name}' cannot be modified"
106
+ )
107
+
108
+ def __delattr__(
109
+ self,
110
+ name: str,
111
+ ) -> None:
112
+ raise AttributeError(
113
+ f"Can't modify immutable {self.__class__.__qualname__},"
114
+ f" attribute - '{name}' cannot be deleted"
115
+ )
116
+
71
117
 
72
118
  @dataclass_transform(
73
119
  kw_only_default=True,