haiway 0.25.1__py3-none-any.whl → 0.26.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/__init__.py +2 -4
- haiway/context/__init__.py +2 -2
- haiway/context/access.py +152 -198
- haiway/context/presets.py +104 -86
- haiway/context/state.py +2 -42
- haiway/helpers/__init__.py +0 -2
- {haiway-0.25.1.dist-info → haiway-0.26.0.dist-info}/METADATA +1 -1
- {haiway-0.25.1.dist-info → haiway-0.26.0.dist-info}/RECORD +10 -11
- haiway/helpers/tracing.py +0 -185
- {haiway-0.25.1.dist-info → haiway-0.26.0.dist-info}/WHEEL +0 -0
- {haiway-0.25.1.dist-info → haiway-0.26.0.dist-info}/licenses/LICENSE +0 -0
haiway/context/access.py
CHANGED
@@ -13,6 +13,7 @@ from collections.abc import (
|
|
13
13
|
Iterable,
|
14
14
|
Mapping,
|
15
15
|
)
|
16
|
+
from contextlib import AbstractAsyncContextManager, AbstractContextManager
|
16
17
|
from logging import Logger
|
17
18
|
from types import TracebackType
|
18
19
|
from typing import Any, final, overload
|
@@ -25,38 +26,28 @@ from haiway.context.observability import (
|
|
25
26
|
ObservabilityContext,
|
26
27
|
ObservabilityLevel,
|
27
28
|
)
|
29
|
+
|
30
|
+
# Import after other imports to avoid circular dependencies
|
28
31
|
from haiway.context.presets import (
|
29
|
-
|
30
|
-
|
31
|
-
ContextPresetsRegistryContext,
|
32
|
+
ContextPreset,
|
33
|
+
ContextPresetRegistryContext,
|
32
34
|
)
|
33
35
|
from haiway.context.state import ScopeState, StateContext
|
34
36
|
from haiway.context.tasks import TaskGroupContext
|
35
37
|
from haiway.state import Immutable, State
|
38
|
+
from haiway.utils.collections import as_list
|
36
39
|
from haiway.utils.stream import AsyncStream
|
37
40
|
|
38
41
|
__all__ = ("ctx",)
|
39
42
|
|
40
43
|
|
41
44
|
class ScopeContext(Immutable):
|
42
|
-
"""
|
43
|
-
Context manager for executing code within a defined scope.
|
44
|
-
|
45
|
-
ScopeContext manages scope-related data and behavior including identity, state,
|
46
|
-
observability, and task coordination. It enforces immutability and provides both
|
47
|
-
synchronous and asynchronous context management interfaces.
|
48
|
-
|
49
|
-
This class should not be instantiated directly; use the ctx.scope() factory method
|
50
|
-
to create scope contexts.
|
51
|
-
"""
|
52
|
-
|
53
45
|
_identifier: ScopeIdentifier
|
54
46
|
_state: Collection[State]
|
55
|
-
|
56
|
-
_resolved_state_context: StateContext | None
|
47
|
+
_state_context: StateContext | None
|
57
48
|
_disposables: Disposables | None
|
58
|
-
|
59
|
-
|
49
|
+
_preset: ContextPreset | None
|
50
|
+
_preset_disposables: Disposables | None
|
60
51
|
_observability_context: ObservabilityContext
|
61
52
|
_task_group_context: TaskGroupContext | None
|
62
53
|
|
@@ -65,6 +56,7 @@ class ScopeContext(Immutable):
|
|
65
56
|
name: str,
|
66
57
|
task_group: TaskGroup | None,
|
67
58
|
state: tuple[State, ...],
|
59
|
+
preset: ContextPreset | None,
|
68
60
|
disposables: Disposables | None,
|
69
61
|
observability: Observability | Logger | None,
|
70
62
|
) -> None:
|
@@ -79,16 +71,10 @@ class ScopeContext(Immutable):
|
|
79
71
|
"_state",
|
80
72
|
state,
|
81
73
|
)
|
82
|
-
# capture current contextual state (without new additions)
|
83
|
-
object.__setattr__(
|
84
|
-
self,
|
85
|
-
"_captured_state",
|
86
|
-
StateContext.current_state(),
|
87
|
-
)
|
88
74
|
# placeholder for temporary, resolved state context
|
89
75
|
object.__setattr__(
|
90
76
|
self,
|
91
|
-
"
|
77
|
+
"_state_context",
|
92
78
|
None,
|
93
79
|
)
|
94
80
|
object.__setattr__(
|
@@ -98,12 +84,12 @@ class ScopeContext(Immutable):
|
|
98
84
|
)
|
99
85
|
object.__setattr__(
|
100
86
|
self,
|
101
|
-
"
|
102
|
-
|
87
|
+
"_preset",
|
88
|
+
preset if preset is not None else ContextPresetRegistryContext.select(name),
|
103
89
|
)
|
104
90
|
object.__setattr__(
|
105
91
|
self,
|
106
|
-
"
|
92
|
+
"_preset_disposables",
|
107
93
|
None,
|
108
94
|
)
|
109
95
|
object.__setattr__(
|
@@ -123,80 +109,28 @@ class ScopeContext(Immutable):
|
|
123
109
|
else None,
|
124
110
|
)
|
125
111
|
|
126
|
-
def __enter__(self) -> str:
|
127
|
-
assert ( # nosec: B101
|
128
|
-
self._task_group_context is None or self._identifier.is_root
|
129
|
-
), "Can't enter synchronous context with task group"
|
130
|
-
assert self._disposables is None, "Can't enter synchronous context with disposables" # nosec: B101
|
131
|
-
assert self._resolved_state_context is None # nosec: B101
|
132
|
-
assert self._presets is None, "Can't enter synchronous context with presets" # nosec: B101
|
133
|
-
self._identifier.__enter__()
|
134
|
-
self._observability_context.__enter__()
|
135
|
-
# For sync context, only use explicit state (no presets or disposables allowed)
|
136
|
-
resolved_state_context: StateContext = StateContext(
|
137
|
-
_state=ScopeState((*self._captured_state, *self._state))
|
138
|
-
)
|
139
|
-
object.__setattr__(
|
140
|
-
self,
|
141
|
-
"_resolved_state_context",
|
142
|
-
resolved_state_context,
|
143
|
-
)
|
144
|
-
resolved_state_context.__enter__()
|
145
|
-
|
146
|
-
return str(self._observability_context.observability.trace_identifying(self._identifier))
|
147
|
-
|
148
|
-
def __exit__(
|
149
|
-
self,
|
150
|
-
exc_type: type[BaseException] | None,
|
151
|
-
exc_val: BaseException | None,
|
152
|
-
exc_tb: TracebackType | None,
|
153
|
-
) -> None:
|
154
|
-
assert self._resolved_state_context is not None # nosec: B101
|
155
|
-
self._resolved_state_context.__exit__(
|
156
|
-
exc_type=exc_type,
|
157
|
-
exc_val=exc_val,
|
158
|
-
exc_tb=exc_tb,
|
159
|
-
)
|
160
|
-
object.__setattr__(
|
161
|
-
self,
|
162
|
-
"_resolved_state_context",
|
163
|
-
None,
|
164
|
-
)
|
165
|
-
self._observability_context.__exit__(
|
166
|
-
exc_type=exc_type,
|
167
|
-
exc_val=exc_val,
|
168
|
-
exc_tb=exc_tb,
|
169
|
-
)
|
170
|
-
self._identifier.__exit__(
|
171
|
-
exc_type=exc_type,
|
172
|
-
exc_val=exc_val,
|
173
|
-
exc_tb=exc_tb,
|
174
|
-
)
|
175
|
-
|
176
112
|
async def __aenter__(self) -> str:
|
177
|
-
assert self.
|
178
|
-
assert self.
|
113
|
+
assert self._preset_disposables is None # nosec: B101
|
114
|
+
assert self._state_context is None # nosec: B101
|
179
115
|
self._identifier.__enter__()
|
180
116
|
self._observability_context.__enter__()
|
181
117
|
|
182
|
-
if
|
183
|
-
await
|
118
|
+
if self._task_group_context is not None:
|
119
|
+
await self._task_group_context.__aenter__()
|
184
120
|
|
185
121
|
# Collect all state sources in priority order (lowest to highest priority)
|
186
|
-
collected_state: list[State] = []
|
187
|
-
|
188
122
|
# 1. Add contextual state first (lowest priority)
|
189
|
-
collected_state.
|
123
|
+
collected_state: list[State] = as_list(StateContext.current_state())
|
190
124
|
|
191
125
|
# 2. Add preset state (low priority, overrides contextual)
|
192
|
-
if self.
|
193
|
-
|
126
|
+
if self._preset is not None:
|
127
|
+
preset_disposables: Disposables = await self._preset.prepare()
|
194
128
|
object.__setattr__(
|
195
129
|
self,
|
196
|
-
"
|
197
|
-
|
130
|
+
"_preset_disposables",
|
131
|
+
preset_disposables,
|
198
132
|
)
|
199
|
-
collected_state.extend(await
|
133
|
+
collected_state.extend(await preset_disposables.prepare())
|
200
134
|
|
201
135
|
# 3. Add explicit disposables state (medium priority)
|
202
136
|
if self._disposables is not None:
|
@@ -212,7 +146,7 @@ class ScopeContext(Immutable):
|
|
212
146
|
resolved_state_context.__enter__()
|
213
147
|
object.__setattr__(
|
214
148
|
self,
|
215
|
-
"
|
149
|
+
"_state_context",
|
216
150
|
resolved_state_context,
|
217
151
|
)
|
218
152
|
|
@@ -224,7 +158,7 @@ class ScopeContext(Immutable):
|
|
224
158
|
exc_val: BaseException | None,
|
225
159
|
exc_tb: TracebackType | None,
|
226
160
|
) -> None:
|
227
|
-
assert self.
|
161
|
+
assert self._state_context is not None # nosec: B101
|
228
162
|
if self._disposables is not None:
|
229
163
|
await self._disposables.dispose(
|
230
164
|
exc_type=exc_type,
|
@@ -232,42 +166,40 @@ class ScopeContext(Immutable):
|
|
232
166
|
exc_tb=exc_tb,
|
233
167
|
)
|
234
168
|
|
235
|
-
if self.
|
236
|
-
await self.
|
169
|
+
if self._preset_disposables is not None:
|
170
|
+
await self._preset_disposables.dispose(
|
237
171
|
exc_type=exc_type,
|
238
172
|
exc_val=exc_val,
|
239
173
|
exc_tb=exc_tb,
|
240
174
|
)
|
241
175
|
object.__setattr__(
|
242
176
|
self,
|
243
|
-
"
|
177
|
+
"_preset_disposables",
|
244
178
|
None,
|
245
179
|
)
|
246
180
|
|
247
|
-
if
|
248
|
-
await
|
181
|
+
if self._task_group_context is not None:
|
182
|
+
await self._task_group_context.__aexit__(
|
249
183
|
exc_type=exc_type,
|
250
184
|
exc_val=exc_val,
|
251
185
|
exc_tb=exc_tb,
|
252
186
|
)
|
253
187
|
|
254
|
-
self.
|
188
|
+
self._state_context.__exit__(
|
255
189
|
exc_type=exc_type,
|
256
190
|
exc_val=exc_val,
|
257
191
|
exc_tb=exc_tb,
|
258
192
|
)
|
259
193
|
object.__setattr__(
|
260
194
|
self,
|
261
|
-
"
|
195
|
+
"_state_context",
|
262
196
|
None,
|
263
197
|
)
|
264
|
-
|
265
198
|
self._observability_context.__exit__(
|
266
199
|
exc_type=exc_type,
|
267
200
|
exc_val=exc_val,
|
268
201
|
exc_tb=exc_tb,
|
269
202
|
)
|
270
|
-
|
271
203
|
self._identifier.__exit__(
|
272
204
|
exc_type=exc_type,
|
273
205
|
exc_val=exc_val,
|
@@ -276,65 +208,32 @@ class ScopeContext(Immutable):
|
|
276
208
|
|
277
209
|
|
278
210
|
class DisposablesContext(Immutable):
|
279
|
-
"""
|
280
|
-
Immutable async context manager for managing collections of disposables.
|
281
|
-
|
282
|
-
DisposablesContext captures the current contextual state upon initialization
|
283
|
-
and provides an async context manager interface for managing disposable resources.
|
284
|
-
When entered, it prepares the disposables to collect their state, merges it with
|
285
|
-
the captured state, and creates a resolved StateContext. Upon exit, it properly
|
286
|
-
disposes of the disposables and cleans up internal references.
|
287
|
-
|
288
|
-
This class should not be instantiated directly; use the ctx.disposables() factory
|
289
|
-
method to create disposables contexts.
|
290
|
-
"""
|
291
|
-
|
292
211
|
_disposables: Disposables
|
293
|
-
|
294
|
-
_resolved_state_context: StateContext | None
|
212
|
+
_state_context: StateContext | None
|
295
213
|
|
296
214
|
def __init__(
|
297
215
|
self,
|
298
216
|
disposables: Disposables,
|
299
217
|
) -> None:
|
300
|
-
# capture current contextual state (without new additions)
|
301
218
|
object.__setattr__(
|
302
219
|
self,
|
303
|
-
"
|
304
|
-
|
220
|
+
"_disposables",
|
221
|
+
disposables,
|
305
222
|
)
|
306
|
-
# placeholder for temporary, resolved state context
|
307
223
|
object.__setattr__(
|
308
224
|
self,
|
309
|
-
"
|
225
|
+
"_state_context",
|
310
226
|
None,
|
311
227
|
)
|
312
|
-
object.__setattr__(
|
313
|
-
self,
|
314
|
-
"_disposables",
|
315
|
-
disposables,
|
316
|
-
)
|
317
228
|
|
318
229
|
async def __aenter__(self) -> None:
|
319
|
-
assert self.
|
320
|
-
|
321
|
-
|
322
|
-
collected_state: list[State] = []
|
323
|
-
|
324
|
-
collected_state.extend(self._captured_state)
|
325
|
-
|
326
|
-
collected_state.extend(await self._disposables.prepare())
|
327
|
-
|
328
|
-
# Create resolved state context with all collected state
|
329
|
-
resolved_state_context: StateContext = StateContext(
|
330
|
-
_state=ScopeState(tuple(collected_state))
|
331
|
-
)
|
332
|
-
|
333
|
-
resolved_state_context.__enter__()
|
230
|
+
assert self._state_context is None # nosec: B101
|
231
|
+
state_context: StateContext = StateContext.updated(await self._disposables.prepare())
|
232
|
+
state_context.__enter__()
|
334
233
|
object.__setattr__(
|
335
234
|
self,
|
336
|
-
"
|
337
|
-
|
235
|
+
"_state_context",
|
236
|
+
state_context,
|
338
237
|
)
|
339
238
|
|
340
239
|
async def __aexit__(
|
@@ -343,22 +242,20 @@ class DisposablesContext(Immutable):
|
|
343
242
|
exc_val: BaseException | None,
|
344
243
|
exc_tb: TracebackType | None,
|
345
244
|
) -> None:
|
346
|
-
assert self.
|
347
|
-
|
245
|
+
assert self._state_context is not None # nosec: B101
|
348
246
|
await self._disposables.dispose(
|
349
247
|
exc_type=exc_type,
|
350
248
|
exc_val=exc_val,
|
351
249
|
exc_tb=exc_tb,
|
352
250
|
)
|
353
|
-
|
354
|
-
self._resolved_state_context.__exit__(
|
251
|
+
self._state_context.__exit__(
|
355
252
|
exc_type=exc_type,
|
356
253
|
exc_val=exc_val,
|
357
254
|
exc_tb=exc_tb,
|
358
255
|
)
|
359
256
|
object.__setattr__(
|
360
257
|
self,
|
361
|
-
"
|
258
|
+
"_state_context",
|
362
259
|
None,
|
363
260
|
)
|
364
261
|
|
@@ -406,8 +303,8 @@ class ctx:
|
|
406
303
|
|
407
304
|
@staticmethod
|
408
305
|
def presets(
|
409
|
-
*presets:
|
410
|
-
) ->
|
306
|
+
*presets: ContextPreset,
|
307
|
+
) -> AbstractContextManager[None]:
|
411
308
|
"""
|
412
309
|
Create a context manager for a preset registry.
|
413
310
|
|
@@ -419,15 +316,19 @@ class ctx:
|
|
419
316
|
for use with ctx.scope(). The presets are looked up by their name when
|
420
317
|
creating scopes.
|
421
318
|
|
319
|
+
Note: For single preset usage, consider passing the preset directly to
|
320
|
+
ctx.scope() using the preset parameter instead of using this registry.
|
321
|
+
Presets only work with async contexts.
|
322
|
+
|
422
323
|
Parameters
|
423
324
|
----------
|
424
|
-
*presets:
|
325
|
+
*presets: ContextPreset
|
425
326
|
Variable number of preset configurations to register. Each preset
|
426
327
|
must have a unique name within the registry.
|
427
328
|
|
428
329
|
Returns
|
429
330
|
-------
|
430
|
-
|
331
|
+
AbstractContextManager[None]
|
431
332
|
A context manager that makes the presets available in nested scopes
|
432
333
|
|
433
334
|
Examples
|
@@ -435,19 +336,19 @@ class ctx:
|
|
435
336
|
Basic preset usage:
|
436
337
|
|
437
338
|
>>> from haiway import ctx, State
|
438
|
-
>>> from haiway.context import
|
339
|
+
>>> from haiway.context import ContextPreset
|
439
340
|
>>>
|
440
341
|
>>> class ApiConfig(State):
|
441
342
|
... base_url: str
|
442
343
|
... timeout: int = 30
|
443
344
|
>>>
|
444
345
|
>>> # Define presets
|
445
|
-
>>> dev_preset =
|
346
|
+
>>> dev_preset = ContextPreset(
|
446
347
|
... name="development",
|
447
348
|
... _state=[ApiConfig(base_url="https://dev-api.example.com")]
|
448
349
|
... )
|
449
350
|
>>>
|
450
|
-
>>> prod_preset =
|
351
|
+
>>> prod_preset = ContextPreset(
|
451
352
|
... name="production",
|
452
353
|
... _state=[ApiConfig(base_url="https://api.example.com", timeout=60)]
|
453
354
|
... )
|
@@ -461,7 +362,7 @@ class ctx:
|
|
461
362
|
Nested preset registries:
|
462
363
|
|
463
364
|
>>> base_presets = [dev_preset, prod_preset]
|
464
|
-
>>> override_preset =
|
365
|
+
>>> override_preset = ContextPreset(
|
465
366
|
... name="development",
|
466
367
|
... _state=[ApiConfig(base_url="https://staging.example.com")]
|
467
368
|
... )
|
@@ -476,27 +377,29 @@ class ctx:
|
|
476
377
|
|
477
378
|
See Also
|
478
379
|
--------
|
479
|
-
|
380
|
+
ContextPreset : For creating individual preset configurations
|
480
381
|
ctx.scope : For creating scopes that can use presets
|
481
382
|
"""
|
482
|
-
return
|
483
|
-
registry=ContextPresetsRegistry(
|
484
|
-
presets=presets,
|
485
|
-
),
|
486
|
-
)
|
383
|
+
return ContextPresetRegistryContext(presets=presets)
|
487
384
|
|
488
385
|
@staticmethod
|
489
386
|
def scope(
|
490
387
|
name: str,
|
491
388
|
/,
|
492
389
|
*state: State | None,
|
390
|
+
preset: ContextPreset | None = None,
|
493
391
|
disposables: Disposables | Iterable[Disposable] | None = None,
|
494
392
|
task_group: TaskGroup | None = None,
|
495
393
|
observability: Observability | Logger | None = None,
|
496
|
-
) ->
|
394
|
+
) -> AbstractAsyncContextManager[str]:
|
497
395
|
"""
|
498
|
-
Prepare scope context with given parameters.
|
499
|
-
|
396
|
+
Prepare scope context with given parameters.
|
397
|
+
|
398
|
+
When called within an existing context, it becomes nested with current context
|
399
|
+
as its parent.
|
400
|
+
|
401
|
+
Note: Presets can only be used with async contexts. Synchronous contexts
|
402
|
+
do not support preset functionality.
|
500
403
|
|
501
404
|
State Priority System
|
502
405
|
---------------------
|
@@ -516,28 +419,71 @@ class ctx:
|
|
516
419
|
name of the scope context, can be associated with state presets
|
517
420
|
|
518
421
|
*state: State | None
|
519
|
-
state propagated within the scope context, will be merged with current state by
|
520
|
-
|
422
|
+
state propagated within the scope context, will be merged with current state by
|
423
|
+
replacing current with provided on conflict.
|
424
|
+
|
425
|
+
preset: ContextPreset | None = None
|
426
|
+
context preset to be used within the scope context. The preset's state and
|
427
|
+
disposables will be applied to the scope with lower priority than explicit state.
|
428
|
+
Only works with async contexts.
|
521
429
|
|
522
430
|
disposables: Disposables | Iterable[Disposable] | None
|
523
|
-
disposables consumed within the context when entered. Produced state will automatically
|
524
|
-
|
525
|
-
|
431
|
+
disposables consumed within the context when entered. Produced state will automatically
|
432
|
+
be added to the scope state. Using asynchronous context is required if any disposables
|
433
|
+
were provided.
|
526
434
|
|
527
435
|
task_group: TaskGroup | None
|
528
436
|
task group used for spawning and joining tasks within the context. Root scope will
|
529
|
-
|
437
|
+
always have task group created even when not set.
|
530
438
|
|
531
439
|
observability: Observability | Logger | None = None
|
532
|
-
observability solution responsible for recording and storing metrics, logs and events
|
533
|
-
|
440
|
+
observability solution responsible for recording and storing metrics, logs and events.
|
441
|
+
Assigning observability within existing context will result in an error.
|
534
442
|
When not provided, logger with the scope name will be requested and used.
|
535
443
|
|
536
444
|
Returns
|
537
445
|
-------
|
538
|
-
|
539
|
-
context object intended to enter
|
540
|
-
|
446
|
+
AbstractAsyncContextManager[str]
|
447
|
+
context manager object intended to enter the scope with.
|
448
|
+
context manager will provide trace_id of current scope.
|
449
|
+
|
450
|
+
Examples
|
451
|
+
--------
|
452
|
+
Using a preset directly:
|
453
|
+
|
454
|
+
>>> from haiway import ctx, State
|
455
|
+
>>> from haiway.context import ContextPreset
|
456
|
+
>>>
|
457
|
+
>>> class ApiConfig(State):
|
458
|
+
... base_url: str
|
459
|
+
... timeout: int = 30
|
460
|
+
>>>
|
461
|
+
>>> api_preset = ContextPreset(
|
462
|
+
... name="api",
|
463
|
+
... state=[ApiConfig(base_url="https://api.example.com")]
|
464
|
+
... )
|
465
|
+
>>>
|
466
|
+
>>> # Direct preset usage
|
467
|
+
>>> async with ctx.scope("main", preset=api_preset):
|
468
|
+
... config = ctx.state(ApiConfig)
|
469
|
+
... # Uses preset configuration
|
470
|
+
>>>
|
471
|
+
>>> # Override preset state with explicit state
|
472
|
+
>>> async with ctx.scope("main", ApiConfig(timeout=60), preset=api_preset):
|
473
|
+
... config = ctx.state(ApiConfig)
|
474
|
+
... # base_url from preset, timeout overridden to 60
|
475
|
+
|
476
|
+
Using preset registry (original approach):
|
477
|
+
|
478
|
+
>>> # Multiple presets registered
|
479
|
+
>>> with ctx.presets(dev_preset, prod_preset):
|
480
|
+
... async with ctx.scope("development"): # Matches dev_preset by name
|
481
|
+
... config = ctx.state(ApiConfig)
|
482
|
+
|
483
|
+
See Also
|
484
|
+
--------
|
485
|
+
ctx.presets : For registering multiple presets by name
|
486
|
+
ContextPreset : For creating preset configurations
|
541
487
|
"""
|
542
488
|
|
543
489
|
resolved_disposables: Disposables | None
|
@@ -555,6 +501,7 @@ class ctx:
|
|
555
501
|
name=name,
|
556
502
|
task_group=task_group,
|
557
503
|
state=tuple(element for element in state if element is not None),
|
504
|
+
preset=preset,
|
558
505
|
disposables=resolved_disposables,
|
559
506
|
observability=observability,
|
560
507
|
)
|
@@ -562,21 +509,23 @@ class ctx:
|
|
562
509
|
@staticmethod
|
563
510
|
def updated(
|
564
511
|
*state: State | None,
|
565
|
-
) ->
|
512
|
+
) -> AbstractContextManager[None]:
|
566
513
|
"""
|
567
|
-
Update scope context with given state.
|
568
|
-
|
514
|
+
Update scope context with given state.
|
515
|
+
|
516
|
+
When called within an existing context, it becomes nested with current
|
517
|
+
context as its predecessor.
|
569
518
|
|
570
519
|
Parameters
|
571
520
|
----------
|
572
521
|
*state: State | None
|
573
|
-
state propagated within the updated scope context, will be merged with current if any
|
574
|
-
|
522
|
+
state propagated within the updated scope context, will be merged with current if any
|
523
|
+
by replacing current with provided on conflict
|
575
524
|
|
576
525
|
Returns
|
577
526
|
-------
|
578
|
-
|
579
|
-
|
527
|
+
AbstractContextManager[None]
|
528
|
+
context manager object intended to enter updated state context with it
|
580
529
|
"""
|
581
530
|
|
582
531
|
return StateContext.updated(element for element in state if element is not None)
|
@@ -584,7 +533,7 @@ class ctx:
|
|
584
533
|
@staticmethod
|
585
534
|
def disposables(
|
586
535
|
*disposables: Disposable | None,
|
587
|
-
) ->
|
536
|
+
) -> AbstractAsyncContextManager[None]:
|
588
537
|
"""
|
589
538
|
Create a container for managing multiple disposable resources.
|
590
539
|
|
@@ -601,9 +550,9 @@ class ctx:
|
|
601
550
|
|
602
551
|
Returns
|
603
552
|
-------
|
604
|
-
|
605
|
-
A
|
606
|
-
and propagates their state to the context
|
553
|
+
AbstractAsyncContextManager[None]
|
554
|
+
A context manager that manages the lifecycle of all provided disposables
|
555
|
+
and propagates their state to the context, similar to ctx.scope()
|
607
556
|
|
608
557
|
Examples
|
609
558
|
--------
|
@@ -634,8 +583,9 @@ class ctx:
|
|
634
583
|
**kwargs: Arguments.kwargs,
|
635
584
|
) -> Task[Result]:
|
636
585
|
"""
|
637
|
-
Spawn an async task within current scope context task group.
|
638
|
-
|
586
|
+
Spawn an async task within current scope context task group.
|
587
|
+
|
588
|
+
When called outside of context, it will spawn detached task instead.
|
639
589
|
|
640
590
|
Parameters
|
641
591
|
----------
|
@@ -684,7 +634,7 @@ class ctx:
|
|
684
634
|
"""
|
685
635
|
|
686
636
|
output_stream = AsyncStream[Element]()
|
687
|
-
stream_scope:
|
637
|
+
stream_scope: AbstractAsyncContextManager[str] = ctx.scope("stream")
|
688
638
|
|
689
639
|
async def stream() -> None:
|
690
640
|
async with stream_scope:
|
@@ -845,8 +795,9 @@ class ctx:
|
|
845
795
|
**extra: Any,
|
846
796
|
) -> None:
|
847
797
|
"""
|
848
|
-
Log using ERROR level within current scope context.
|
849
|
-
|
798
|
+
Log using ERROR level within current scope context.
|
799
|
+
|
800
|
+
When there is no current scope, root logger will be used without additional details.
|
850
801
|
|
851
802
|
Parameters
|
852
803
|
----------
|
@@ -881,8 +832,9 @@ class ctx:
|
|
881
832
|
**extra: Any,
|
882
833
|
) -> None:
|
883
834
|
"""
|
884
|
-
Log using WARNING level within current scope context.
|
885
|
-
|
835
|
+
Log using WARNING level within current scope context.
|
836
|
+
|
837
|
+
When there is no current scope, root logger will be used without additional details.
|
886
838
|
|
887
839
|
Parameters
|
888
840
|
----------
|
@@ -916,8 +868,9 @@ class ctx:
|
|
916
868
|
**extra: Any,
|
917
869
|
) -> None:
|
918
870
|
"""
|
919
|
-
Log using INFO level within current scope context.
|
920
|
-
|
871
|
+
Log using INFO level within current scope context.
|
872
|
+
|
873
|
+
When there is no current scope, root logger will be used without additional details.
|
921
874
|
|
922
875
|
Parameters
|
923
876
|
----------
|
@@ -949,8 +902,9 @@ class ctx:
|
|
949
902
|
**extra: Any,
|
950
903
|
) -> None:
|
951
904
|
"""
|
952
|
-
Log using DEBUG level within current scope context.
|
953
|
-
|
905
|
+
Log using DEBUG level within current scope context.
|
906
|
+
|
907
|
+
When there is no current scope, root logger will be used without additional details.
|
954
908
|
|
955
909
|
Parameters
|
956
910
|
----------
|