omlish 0.0.0.dev484__py3-none-any.whl → 0.0.0.dev493__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.
Potentially problematic release.
This version of omlish might be problematic. Click here for more details.
- omlish/README.md +199 -0
- omlish/__about__.py +8 -3
- omlish/dataclasses/impl/generation/plans.py +2 -17
- omlish/dataclasses/impl/generation/processor.py +2 -2
- omlish/dataclasses/impl/processing/driving.py +13 -1
- omlish/diag/_pycharm/runhack.py +1 -1
- omlish/inject/__init__.py +19 -11
- omlish/inject/_dataclasses.py +1485 -1323
- omlish/inject/binder.py +7 -4
- omlish/inject/eagers.py +2 -0
- omlish/inject/helpers/late.py +76 -0
- omlish/inject/{managed.py → helpers/managed.py} +10 -10
- omlish/inject/impl/elements.py +7 -4
- omlish/inject/impl/injector.py +10 -7
- omlish/inject/inspect.py +1 -1
- omlish/lang/__init__.py +2 -0
- omlish/lifecycles/README.md +30 -0
- omlish/lifecycles/__init__.py +87 -13
- omlish/lifecycles/_dataclasses.py +1388 -0
- omlish/lifecycles/base.py +178 -64
- omlish/lifecycles/contextmanagers.py +113 -4
- omlish/lifecycles/controller.py +150 -87
- omlish/lifecycles/injection.py +143 -0
- omlish/lifecycles/listeners.py +56 -0
- omlish/lifecycles/managed.py +142 -0
- omlish/lifecycles/manager.py +218 -93
- omlish/lifecycles/states.py +2 -0
- omlish/lifecycles/transitions.py +3 -0
- omlish/lifecycles/unwrap.py +57 -0
- omlish/lite/typing.py +18 -0
- omlish/logs/_amalg.py +1 -1
- omlish/logs/all.py +25 -11
- omlish/logs/asyncs.py +73 -0
- omlish/logs/base.py +101 -12
- omlish/logs/contexts.py +4 -1
- omlish/logs/lists.py +125 -0
- omlish/logs/modules.py +19 -1
- omlish/logs/std/loggers.py +6 -1
- omlish/logs/std/noisy.py +11 -9
- omlish/logs/{standard.py → std/standard.py} +3 -4
- omlish/logs/utils.py +16 -1
- omlish/marshal/_dataclasses.py +781 -781
- omlish/reflect/__init__.py +43 -26
- omlish/reflect/ops.py +10 -1
- omlish/specs/jmespath/_dataclasses.py +559 -559
- omlish/specs/jsonschema/keywords/_dataclasses.py +220 -220
- omlish/sql/__init__.py +24 -5
- omlish/sql/api/dbapi.py +1 -1
- omlish/sql/dbapi/__init__.py +15 -0
- omlish/sql/{dbapi.py → dbapi/drivers.py} +2 -2
- omlish/sql/queries/__init__.py +3 -0
- omlish/testing/pytest/plugins/asyncs/plugin.py +2 -0
- omlish/text/docwrap/cli.py +5 -0
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev493.dist-info}/METADATA +8 -5
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev493.dist-info}/RECORD +61 -51
- omlish/lifecycles/abstract.py +0 -86
- /omlish/inject/{impl → helpers}/proxy.py +0 -0
- /omlish/sql/{abc.py → dbapi/abc.py} +0 -0
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev493.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev493.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev493.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev493.dist-info}/top_level.txt +0 -0
omlish/lifecycles/controller.py
CHANGED
|
@@ -1,163 +1,226 @@
|
|
|
1
|
-
import abc
|
|
2
1
|
import typing as ta
|
|
3
2
|
|
|
4
3
|
from .. import check
|
|
5
4
|
from .. import lang
|
|
6
|
-
from .base import
|
|
7
|
-
from .base import Lifecycle
|
|
5
|
+
from .base import AsyncLifecycle
|
|
6
|
+
from .base import Lifecycle
|
|
7
|
+
from .listeners import AsyncLifecycleListener
|
|
8
|
+
from .listeners import LifecycleListener
|
|
8
9
|
from .states import LifecycleState
|
|
9
10
|
from .states import LifecycleStates
|
|
10
11
|
from .transitions import LifecycleTransition
|
|
11
12
|
from .transitions import LifecycleTransitions
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
R = ta.TypeVar('R')
|
|
15
|
-
|
|
16
|
-
AnyLifecycleT = ta.TypeVar('AnyLifecycleT', bound='AnyLifecycle')
|
|
17
|
-
|
|
18
|
-
LifecycleT = ta.TypeVar('LifecycleT', bound='Lifecycle')
|
|
19
|
-
|
|
20
|
-
|
|
21
15
|
##
|
|
22
16
|
|
|
23
17
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return None
|
|
27
|
-
|
|
28
|
-
def on_started(self, obj: AnyLifecycleT) -> R | None:
|
|
29
|
-
return None
|
|
30
|
-
|
|
31
|
-
def on_stopping(self, obj: AnyLifecycleT) -> R | None:
|
|
32
|
-
return None
|
|
33
|
-
|
|
34
|
-
def on_stopped(self, obj: AnyLifecycleT) -> R | None:
|
|
35
|
-
return None
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class AnyLifecycleController(AnyLifecycle[R], lang.Abstract, ta.Generic[AnyLifecycleT, R]):
|
|
18
|
+
@ta.final
|
|
19
|
+
class LifecycleController(Lifecycle, lang.Final):
|
|
39
20
|
def __init__(
|
|
40
21
|
self,
|
|
41
|
-
|
|
22
|
+
controlled: Lifecycle,
|
|
23
|
+
*,
|
|
24
|
+
lock: lang.DefaultLockable = None,
|
|
42
25
|
) -> None:
|
|
43
26
|
super().__init__()
|
|
44
27
|
|
|
45
|
-
self.
|
|
28
|
+
self._controlled: Lifecycle = check.isinstance(controlled, Lifecycle)
|
|
29
|
+
self._lock = lang.default_lock(lock, None)
|
|
46
30
|
|
|
47
31
|
self._state = LifecycleStates.NEW
|
|
48
|
-
self._listeners: list[
|
|
32
|
+
self._listeners: list[LifecycleListener] = []
|
|
33
|
+
|
|
34
|
+
__repr__ = lang.attr_ops(lambda o: (o.controlled, o.state)).repr
|
|
49
35
|
|
|
50
|
-
|
|
36
|
+
#
|
|
51
37
|
|
|
52
38
|
@property
|
|
53
|
-
def
|
|
54
|
-
return self.
|
|
39
|
+
def controlled(self) -> Lifecycle:
|
|
40
|
+
return self._controlled
|
|
55
41
|
|
|
56
42
|
@property
|
|
57
43
|
def state(self) -> LifecycleState:
|
|
58
44
|
return self._state
|
|
59
45
|
|
|
60
|
-
def add_listener(self, listener:
|
|
61
|
-
self._listeners.append(check.isinstance(listener,
|
|
46
|
+
def add_listener(self, listener: LifecycleListener) -> ta.Self:
|
|
47
|
+
self._listeners.append(check.isinstance(listener, LifecycleListener))
|
|
62
48
|
return self
|
|
63
49
|
|
|
64
|
-
|
|
50
|
+
#
|
|
51
|
+
|
|
52
|
+
def _set_state(self, state: LifecycleState) -> None:
|
|
53
|
+
self._state = state
|
|
54
|
+
self._controlled.lifecycle_state(state)
|
|
55
|
+
|
|
65
56
|
def _advance(
|
|
66
57
|
self,
|
|
67
58
|
transition: LifecycleTransition,
|
|
68
|
-
|
|
69
|
-
pre_listener_fn: ta.Callable[
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
59
|
+
controlled_fn: ta.Callable[[], None],
|
|
60
|
+
pre_listener_fn: ta.Callable[[LifecycleListener], ta.Callable[[Lifecycle], None]] | None = None,
|
|
61
|
+
post_listener_fn: ta.Callable[[LifecycleListener], ta.Callable[[Lifecycle], None]] | None = None,
|
|
62
|
+
) -> None:
|
|
63
|
+
with self._lock():
|
|
64
|
+
if pre_listener_fn is not None:
|
|
65
|
+
for listener in self._listeners:
|
|
66
|
+
pre_listener_fn(listener)(self._controlled)
|
|
67
|
+
|
|
68
|
+
check.state(self._state in transition.old)
|
|
69
|
+
self._set_state(transition.new_intermediate)
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
controlled_fn()
|
|
73
|
+
except Exception:
|
|
74
|
+
self._set_state(transition.new_failed)
|
|
75
|
+
raise
|
|
76
|
+
|
|
77
|
+
self._set_state(transition.new_succeeded)
|
|
78
|
+
|
|
79
|
+
if post_listener_fn is not None:
|
|
80
|
+
for listener in self._listeners:
|
|
81
|
+
post_listener_fn(listener)(self._controlled)
|
|
79
82
|
|
|
80
83
|
##
|
|
81
84
|
|
|
82
85
|
@ta.override
|
|
83
|
-
def lifecycle_construct(self) ->
|
|
84
|
-
|
|
86
|
+
def lifecycle_construct(self) -> None:
|
|
87
|
+
self._advance(
|
|
85
88
|
LifecycleTransitions.CONSTRUCT,
|
|
86
|
-
self.
|
|
89
|
+
self._controlled.lifecycle_construct,
|
|
87
90
|
)
|
|
88
91
|
|
|
89
92
|
@ta.override
|
|
90
|
-
def lifecycle_start(self) ->
|
|
91
|
-
|
|
93
|
+
def lifecycle_start(self) -> None:
|
|
94
|
+
self._advance(
|
|
92
95
|
LifecycleTransitions.START,
|
|
93
|
-
self.
|
|
96
|
+
self._controlled.lifecycle_start,
|
|
94
97
|
lambda l: l.on_starting,
|
|
95
98
|
lambda l: l.on_started,
|
|
96
99
|
)
|
|
97
100
|
|
|
98
101
|
@ta.override
|
|
99
|
-
def lifecycle_stop(self) ->
|
|
100
|
-
|
|
102
|
+
def lifecycle_stop(self) -> None:
|
|
103
|
+
self._advance(
|
|
101
104
|
LifecycleTransitions.STOP,
|
|
102
|
-
self.
|
|
105
|
+
self._controlled.lifecycle_stop,
|
|
103
106
|
lambda l: l.on_stopping,
|
|
104
107
|
lambda l: l.on_stopped,
|
|
105
108
|
)
|
|
106
109
|
|
|
107
110
|
@ta.override
|
|
108
|
-
def lifecycle_destroy(self) ->
|
|
109
|
-
|
|
111
|
+
def lifecycle_destroy(self) -> None:
|
|
112
|
+
self._advance(
|
|
110
113
|
LifecycleTransitions.DESTROY,
|
|
111
|
-
self.
|
|
114
|
+
self._controlled.lifecycle_destroy,
|
|
112
115
|
)
|
|
113
116
|
|
|
114
117
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
LifecycleListener: ta.TypeAlias = AnyLifecycleListener[LifecycleT, None]
|
|
118
|
+
#
|
|
119
119
|
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
Lifecycle,
|
|
124
|
-
ta.Generic[LifecycleT],
|
|
125
|
-
):
|
|
121
|
+
@ta.final
|
|
122
|
+
class AsyncLifecycleController(AsyncLifecycle, lang.Final):
|
|
126
123
|
def __init__(
|
|
127
124
|
self,
|
|
128
|
-
|
|
125
|
+
controlled: AsyncLifecycle,
|
|
129
126
|
*,
|
|
130
|
-
lock: lang.
|
|
127
|
+
lock: lang.DefaultAsyncLockable = None,
|
|
131
128
|
) -> None:
|
|
132
|
-
super().__init__(
|
|
129
|
+
super().__init__()
|
|
133
130
|
|
|
134
|
-
self.
|
|
131
|
+
self._controlled: AsyncLifecycle = check.isinstance(controlled, AsyncLifecycle)
|
|
132
|
+
self._lock = lang.default_async_lock(lock, None)
|
|
135
133
|
|
|
136
|
-
|
|
134
|
+
self._state = LifecycleStates.NEW
|
|
135
|
+
self._listeners: list[AsyncLifecycleListener] = []
|
|
136
|
+
|
|
137
|
+
__repr__ = lang.attr_ops(lambda o: (o.controlled, o.state)).repr
|
|
138
|
+
|
|
139
|
+
#
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def controlled(self) -> AsyncLifecycle:
|
|
143
|
+
return self._controlled
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def state(self) -> LifecycleState:
|
|
147
|
+
return self._state
|
|
148
|
+
|
|
149
|
+
def add_listener(self, listener: AsyncLifecycleListener) -> ta.Self:
|
|
150
|
+
self._listeners.append(check.isinstance(listener, AsyncLifecycleListener))
|
|
151
|
+
return self
|
|
152
|
+
|
|
153
|
+
#
|
|
154
|
+
|
|
155
|
+
async def _set_state(self, state: LifecycleState) -> None:
|
|
156
|
+
self._state = state
|
|
157
|
+
await self._controlled.lifecycle_state(state)
|
|
158
|
+
|
|
159
|
+
async def _advance(
|
|
137
160
|
self,
|
|
138
161
|
transition: LifecycleTransition,
|
|
139
|
-
|
|
140
|
-
pre_listener_fn: ta.Callable[
|
|
141
|
-
|
|
142
|
-
ta.Callable[[LifecycleT], None],
|
|
143
|
-
] | None = None,
|
|
144
|
-
post_listener_fn: ta.Callable[
|
|
145
|
-
[LifecycleListener[LifecycleT]],
|
|
146
|
-
ta.Callable[[LifecycleT], None],
|
|
147
|
-
] | None = None,
|
|
162
|
+
controlled_fn: ta.Callable[[], ta.Awaitable[None]],
|
|
163
|
+
pre_listener_fn: ta.Callable[[AsyncLifecycleListener], ta.Callable[[AsyncLifecycle], ta.Awaitable[None]]] | None = None, # noqa
|
|
164
|
+
post_listener_fn: ta.Callable[[AsyncLifecycleListener], ta.Callable[[AsyncLifecycle], ta.Awaitable[None]]] | None = None, # noqa
|
|
148
165
|
) -> None:
|
|
149
|
-
with self._lock():
|
|
166
|
+
async with self._lock():
|
|
150
167
|
if pre_listener_fn is not None:
|
|
151
168
|
for listener in self._listeners:
|
|
152
|
-
pre_listener_fn(listener)(self.
|
|
169
|
+
await pre_listener_fn(listener)(self._controlled)
|
|
170
|
+
|
|
153
171
|
check.state(self._state in transition.old)
|
|
154
|
-
self.
|
|
172
|
+
await self._set_state(transition.new_intermediate)
|
|
173
|
+
|
|
155
174
|
try:
|
|
156
|
-
|
|
175
|
+
await controlled_fn()
|
|
157
176
|
except Exception:
|
|
158
|
-
self.
|
|
177
|
+
await self._set_state(transition.new_failed)
|
|
159
178
|
raise
|
|
160
|
-
|
|
179
|
+
|
|
180
|
+
await self._set_state(transition.new_succeeded)
|
|
181
|
+
|
|
161
182
|
if post_listener_fn is not None:
|
|
162
183
|
for listener in self._listeners:
|
|
163
|
-
post_listener_fn(listener)(self.
|
|
184
|
+
await post_listener_fn(listener)(self._controlled)
|
|
185
|
+
|
|
186
|
+
##
|
|
187
|
+
|
|
188
|
+
@ta.override
|
|
189
|
+
async def lifecycle_construct(self) -> None:
|
|
190
|
+
await self._advance(
|
|
191
|
+
LifecycleTransitions.CONSTRUCT,
|
|
192
|
+
self._controlled.lifecycle_construct,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
@ta.override
|
|
196
|
+
async def lifecycle_start(self) -> None:
|
|
197
|
+
await self._advance(
|
|
198
|
+
LifecycleTransitions.START,
|
|
199
|
+
self._controlled.lifecycle_start,
|
|
200
|
+
lambda l: l.on_starting,
|
|
201
|
+
lambda l: l.on_started,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
@ta.override
|
|
205
|
+
async def lifecycle_stop(self) -> None:
|
|
206
|
+
await self._advance(
|
|
207
|
+
LifecycleTransitions.STOP,
|
|
208
|
+
self._controlled.lifecycle_stop,
|
|
209
|
+
lambda l: l.on_stopping,
|
|
210
|
+
lambda l: l.on_stopped,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
@ta.override
|
|
214
|
+
async def lifecycle_destroy(self) -> None:
|
|
215
|
+
await self._advance(
|
|
216
|
+
LifecycleTransitions.DESTROY,
|
|
217
|
+
self._controlled.lifecycle_destroy,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
#
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
AnyLifecycleController: ta.TypeAlias = LifecycleController | AsyncLifecycleController
|
|
225
|
+
|
|
226
|
+
ANY_LIFECYCLE_CONTROLLER_TYPES: tuple[type[LifecycleController | AsyncLifecycleController], ...] = (LifecycleController, AsyncLifecycleController) # noqa
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from .. import check
|
|
5
|
+
from .. import collections as col
|
|
6
|
+
from .. import dataclasses as dc
|
|
7
|
+
from .. import inject as inj
|
|
8
|
+
from .. import lang
|
|
9
|
+
from .base import AsyncLifecycle
|
|
10
|
+
from .base import Lifecycle
|
|
11
|
+
from .contextmanagers import async_lifecycle_context_manage
|
|
12
|
+
from .contextmanagers import lifecycle_context_manage
|
|
13
|
+
from .manager import AsyncLifecycleManager
|
|
14
|
+
from .manager import LifecycleManager
|
|
15
|
+
from .unwrap import unwrap_any_lifecycle
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@ta.final
|
|
22
|
+
class _LifecycleRegistrar(lang.Final):
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
lifecycle_manager_cls: type[LifecycleManager | AsyncLifecycleManager],
|
|
26
|
+
lifecycle_cls_tup: tuple[type[Lifecycle | AsyncLifecycle], ...],
|
|
27
|
+
*,
|
|
28
|
+
unwrap: bool = False,
|
|
29
|
+
) -> None:
|
|
30
|
+
super().__init__()
|
|
31
|
+
|
|
32
|
+
self._lifecycle_manager_cls = lifecycle_manager_cls
|
|
33
|
+
self._lifecycle_cls_tup = lifecycle_cls_tup
|
|
34
|
+
self._unwrap = unwrap
|
|
35
|
+
|
|
36
|
+
self._seen: ta.MutableSet[ta.Any] = col.IdentityWeakSet()
|
|
37
|
+
self._stack: list[_LifecycleRegistrar.State] = []
|
|
38
|
+
|
|
39
|
+
@ta.final
|
|
40
|
+
@dc.dataclass(frozen=True)
|
|
41
|
+
class Dep(lang.Final):
|
|
42
|
+
binding: inj.Binding | None
|
|
43
|
+
obj: ta.Any
|
|
44
|
+
lco: ta.Any
|
|
45
|
+
|
|
46
|
+
@ta.final
|
|
47
|
+
@dc.dataclass(frozen=True)
|
|
48
|
+
class State(lang.Final):
|
|
49
|
+
key: inj.Key
|
|
50
|
+
deps: list['_LifecycleRegistrar.Dep'] = dc.field(default_factory=list)
|
|
51
|
+
|
|
52
|
+
async def _on_provision(
|
|
53
|
+
self,
|
|
54
|
+
injector: inj.AsyncInjector,
|
|
55
|
+
key: inj.Key,
|
|
56
|
+
binding: inj.Binding | None,
|
|
57
|
+
fn: ta.Callable[[], ta.Awaitable[ta.Any]],
|
|
58
|
+
) -> ta.Awaitable[ta.Any]:
|
|
59
|
+
st = _LifecycleRegistrar.State(key)
|
|
60
|
+
self._stack.append(st)
|
|
61
|
+
try:
|
|
62
|
+
obj = await fn()
|
|
63
|
+
finally:
|
|
64
|
+
popped = self._stack.pop()
|
|
65
|
+
check.state(popped is st)
|
|
66
|
+
|
|
67
|
+
lco: ta.Any
|
|
68
|
+
if self._unwrap:
|
|
69
|
+
lco = unwrap_any_lifecycle(obj)
|
|
70
|
+
else:
|
|
71
|
+
lco = obj
|
|
72
|
+
|
|
73
|
+
if (
|
|
74
|
+
lco is not None and
|
|
75
|
+
isinstance(lco, self._lifecycle_cls_tup) and
|
|
76
|
+
not isinstance(obj, self._lifecycle_manager_cls)
|
|
77
|
+
):
|
|
78
|
+
if self._stack:
|
|
79
|
+
self._stack[-1].deps.append(_LifecycleRegistrar.Dep(binding, obj, lco))
|
|
80
|
+
|
|
81
|
+
if obj not in self._seen:
|
|
82
|
+
mgr = await injector[self._lifecycle_manager_cls]
|
|
83
|
+
|
|
84
|
+
dep_lcos = [d.lco for d in st.deps]
|
|
85
|
+
|
|
86
|
+
if isinstance(mgr, AsyncLifecycleManager):
|
|
87
|
+
await mgr.add(lco, dep_lcos)
|
|
88
|
+
elif isinstance(mgr, LifecycleManager):
|
|
89
|
+
mgr.add(lco, dep_lcos)
|
|
90
|
+
else:
|
|
91
|
+
raise TypeError(mgr)
|
|
92
|
+
|
|
93
|
+
self._seen.add(obj)
|
|
94
|
+
|
|
95
|
+
elif self._stack:
|
|
96
|
+
self._stack[-1].deps.extend(st.deps)
|
|
97
|
+
|
|
98
|
+
return obj
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def bind_lifecycle_registrar() -> inj.Elements:
|
|
102
|
+
return inj.as_elements(
|
|
103
|
+
inj.bind(_LifecycleRegistrar, to_const=(lr := _LifecycleRegistrar(
|
|
104
|
+
LifecycleManager,
|
|
105
|
+
(Lifecycle,),
|
|
106
|
+
unwrap=True,
|
|
107
|
+
))),
|
|
108
|
+
inj.bind_provision_listener(lr._on_provision), # noqa
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def bind_async_lifecycle_registrar() -> inj.Elements:
|
|
113
|
+
return inj.as_elements(
|
|
114
|
+
inj.bind(_LifecycleRegistrar, to_const=(lr := _LifecycleRegistrar(
|
|
115
|
+
AsyncLifecycleManager,
|
|
116
|
+
(Lifecycle, AsyncLifecycle),
|
|
117
|
+
unwrap=True,
|
|
118
|
+
))),
|
|
119
|
+
inj.bind_provision_listener(lr._on_provision), # noqa
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
##
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def bind_managed_lifecycle_manager() -> inj.Elements:
|
|
127
|
+
# FIXME: lock?
|
|
128
|
+
def inner(es: contextlib.ExitStack) -> LifecycleManager:
|
|
129
|
+
return es.enter_context(lifecycle_context_manage(LifecycleManager()))
|
|
130
|
+
|
|
131
|
+
return inj.as_elements(
|
|
132
|
+
inj.bind(inner, singleton=True, eager=True),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def bind_async_managed_lifecycle_manager() -> inj.Elements:
|
|
137
|
+
# FIXME: lock?
|
|
138
|
+
async def inner(aes: contextlib.AsyncExitStack) -> AsyncLifecycleManager:
|
|
139
|
+
return await aes.enter_async_context(async_lifecycle_context_manage(AsyncLifecycleManager()))
|
|
140
|
+
|
|
141
|
+
return inj.as_elements(
|
|
142
|
+
inj.bind(inner, singleton=True, eager=True),
|
|
143
|
+
)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from .. import check
|
|
4
|
+
from .base import AsyncLifecycle
|
|
5
|
+
from .base import Lifecycle
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LifecycleListener:
|
|
12
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
13
|
+
super().__init_subclass__(**kwargs)
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
async_lifecycle_listener_cls = AsyncLifecycleListener
|
|
17
|
+
except NameError:
|
|
18
|
+
pass
|
|
19
|
+
else:
|
|
20
|
+
check.not_issubclass(cls, async_lifecycle_listener_cls)
|
|
21
|
+
|
|
22
|
+
def on_starting(self, obj: Lifecycle) -> None:
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
def on_started(self, obj: Lifecycle) -> None:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
def on_stopping(self, obj: Lifecycle) -> None:
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
def on_stopped(self, obj: Lifecycle) -> None:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class AsyncLifecycleListener:
|
|
36
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
37
|
+
super().__init_subclass__(**kwargs)
|
|
38
|
+
|
|
39
|
+
check.not_issubclass(cls, LifecycleListener)
|
|
40
|
+
|
|
41
|
+
async def on_starting(self, obj: AsyncLifecycle) -> None:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
async def on_started(self, obj: AsyncLifecycle) -> None:
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
async def on_stopping(self, obj: AsyncLifecycle) -> None:
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
async def on_stopped(self, obj: AsyncLifecycle) -> None:
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
AnyLifecycleListener: ta.TypeAlias = LifecycleListener | AsyncLifecycleListener
|
|
55
|
+
|
|
56
|
+
ANY_LIFECYCLE_LISTENER_TYPES: tuple[type[LifecycleListener | AsyncLifecycleListener], ...] = (LifecycleListener, AsyncLifecycleListener) # noqa
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from .. import cached
|
|
4
|
+
from .. import check
|
|
5
|
+
from .. import dataclasses as dc
|
|
6
|
+
from .. import lang
|
|
7
|
+
from .base import AsyncLifecycle
|
|
8
|
+
from .base import Lifecycle
|
|
9
|
+
from .states import LifecycleState
|
|
10
|
+
from .states import LifecycleStates
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
LifecycleManagedT = ta.TypeVar('LifecycleManagedT', bound='LifecycleManaged')
|
|
14
|
+
|
|
15
|
+
AsyncLifecycleManagedT = ta.TypeVar('AsyncLifecycleManagedT', bound='AsyncLifecycleManaged')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class LifecycleManaged(lang.Abstract):
|
|
22
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
23
|
+
super().__init_subclass__(**kwargs)
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
async_lifecycle_managed_cls = AsyncLifecycleManaged
|
|
27
|
+
except NameError:
|
|
28
|
+
pass
|
|
29
|
+
else:
|
|
30
|
+
check.not_issubclass(cls, async_lifecycle_managed_cls)
|
|
31
|
+
|
|
32
|
+
@ta.final
|
|
33
|
+
@dc.dataclass(frozen=True)
|
|
34
|
+
class _Lifecycle(
|
|
35
|
+
Lifecycle,
|
|
36
|
+
lang.Final,
|
|
37
|
+
ta.Generic[LifecycleManagedT],
|
|
38
|
+
):
|
|
39
|
+
obj: LifecycleManagedT
|
|
40
|
+
|
|
41
|
+
def lifecycle_state(self, state: LifecycleState) -> None:
|
|
42
|
+
self.obj._lifecycle_state_ = state
|
|
43
|
+
|
|
44
|
+
def lifecycle_construct(self) -> None:
|
|
45
|
+
self.obj._lifecycle_construct() # noqa
|
|
46
|
+
|
|
47
|
+
def lifecycle_start(self) -> None:
|
|
48
|
+
self.obj._lifecycle_start() # noqa
|
|
49
|
+
|
|
50
|
+
def lifecycle_stop(self) -> None:
|
|
51
|
+
self.obj._lifecycle_stop() # noqa
|
|
52
|
+
|
|
53
|
+
def lifecycle_destroy(self) -> None:
|
|
54
|
+
self.obj._lifecycle_destroy() # noqa
|
|
55
|
+
|
|
56
|
+
@ta.final
|
|
57
|
+
@cached.property
|
|
58
|
+
def _lifecycle(self) -> _Lifecycle[ta.Self]:
|
|
59
|
+
return LifecycleManaged._Lifecycle(self)
|
|
60
|
+
|
|
61
|
+
_lifecycle_state_: LifecycleState = LifecycleStates.NEW
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def _lifecycle_state(self) -> LifecycleState:
|
|
65
|
+
return self._lifecycle_state_
|
|
66
|
+
|
|
67
|
+
def _lifecycle_construct(self) -> None:
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
def _lifecycle_start(self) -> None:
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
def _lifecycle_stop(self) -> None:
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
def _lifecycle_destroy(self) -> None:
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
#
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class AsyncLifecycleManaged(lang.Abstract):
|
|
84
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
85
|
+
super().__init_subclass__(**kwargs)
|
|
86
|
+
|
|
87
|
+
check.not_issubclass(cls, LifecycleManaged)
|
|
88
|
+
|
|
89
|
+
@ta.final
|
|
90
|
+
@dc.dataclass(frozen=True)
|
|
91
|
+
class _Lifecycle(
|
|
92
|
+
AsyncLifecycle,
|
|
93
|
+
lang.Final,
|
|
94
|
+
ta.Generic[AsyncLifecycleManagedT],
|
|
95
|
+
):
|
|
96
|
+
obj: AsyncLifecycleManagedT
|
|
97
|
+
|
|
98
|
+
async def lifecycle_state(self, state: LifecycleState) -> None:
|
|
99
|
+
self.obj._lifecycle_state_ = state
|
|
100
|
+
|
|
101
|
+
async def lifecycle_construct(self) -> None:
|
|
102
|
+
await self.obj._lifecycle_construct() # noqa
|
|
103
|
+
|
|
104
|
+
async def lifecycle_start(self) -> None:
|
|
105
|
+
await self.obj._lifecycle_start() # noqa
|
|
106
|
+
|
|
107
|
+
async def lifecycle_stop(self) -> None:
|
|
108
|
+
await self.obj._lifecycle_stop() # noqa
|
|
109
|
+
|
|
110
|
+
async def lifecycle_destroy(self) -> None:
|
|
111
|
+
await self.obj._lifecycle_destroy() # noqa
|
|
112
|
+
|
|
113
|
+
@ta.final
|
|
114
|
+
@cached.property
|
|
115
|
+
def _lifecycle(self) -> _Lifecycle[ta.Self]:
|
|
116
|
+
return AsyncLifecycleManaged._Lifecycle(self)
|
|
117
|
+
|
|
118
|
+
_lifecycle_state_: LifecycleState = LifecycleStates.NEW
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def _lifecycle_state(self) -> LifecycleState:
|
|
122
|
+
return self._lifecycle_state_
|
|
123
|
+
|
|
124
|
+
async def _lifecycle_construct(self) -> None:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
async def _lifecycle_start(self) -> None:
|
|
128
|
+
pass
|
|
129
|
+
|
|
130
|
+
async def _lifecycle_stop(self) -> None:
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
async def _lifecycle_destroy(self) -> None:
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
#
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
AnyLifecycleManaged: ta.TypeAlias = LifecycleManaged | AsyncLifecycleManaged
|
|
141
|
+
|
|
142
|
+
ANY_LIFECYCLE_MANAGED_TYPES: tuple[type[LifecycleManaged | AsyncLifecycleManaged], ...] = (LifecycleManaged, AsyncLifecycleManaged) # noqa
|