engin 0.1a1__py3-none-any.whl → 0.1.0a2__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.
- engin/_engin.py +49 -12
- {engin-0.1a1.dist-info → engin-0.1.0a2.dist-info}/METADATA +2 -2
- {engin-0.1a1.dist-info → engin-0.1.0a2.dist-info}/RECORD +6 -6
- {engin-0.1a1.dist-info → engin-0.1.0a2.dist-info}/WHEEL +0 -0
- {engin-0.1a1.dist-info → engin-0.1.0a2.dist-info}/entry_points.txt +0 -0
- {engin-0.1a1.dist-info → engin-0.1.0a2.dist-info}/licenses/LICENSE +0 -0
engin/_engin.py
CHANGED
@@ -5,6 +5,7 @@ import signal
|
|
5
5
|
from asyncio import Event, Task
|
6
6
|
from collections import defaultdict
|
7
7
|
from contextlib import AsyncExitStack
|
8
|
+
from enum import Enum
|
8
9
|
from itertools import chain
|
9
10
|
from types import FrameType
|
10
11
|
from typing import ClassVar
|
@@ -19,11 +20,39 @@ from engin._option import Option
|
|
19
20
|
from engin._shutdown import ShutdownSwitch
|
20
21
|
from engin._supervisor import Supervisor
|
21
22
|
from engin._type_utils import TypeId
|
23
|
+
from engin.exceptions import EnginError
|
22
24
|
|
23
25
|
_OS_IS_WINDOWS = os.name == "nt"
|
24
26
|
LOG = logging.getLogger("engin")
|
25
27
|
|
26
28
|
|
29
|
+
class _EnginState(Enum):
|
30
|
+
IDLE = 0
|
31
|
+
"""
|
32
|
+
Not yet started.
|
33
|
+
"""
|
34
|
+
|
35
|
+
STARTED = 1
|
36
|
+
"""
|
37
|
+
Engin started via .start() call
|
38
|
+
"""
|
39
|
+
|
40
|
+
RUNNING = 2
|
41
|
+
"""
|
42
|
+
Engin running via .run() call
|
43
|
+
"""
|
44
|
+
|
45
|
+
STOPPING = 3
|
46
|
+
"""
|
47
|
+
Engin stopped via .stop() call
|
48
|
+
"""
|
49
|
+
|
50
|
+
SHUTDOWN = 4
|
51
|
+
"""
|
52
|
+
Engin has performed shutdown
|
53
|
+
"""
|
54
|
+
|
55
|
+
|
27
56
|
class Engin:
|
28
57
|
"""
|
29
58
|
The Engin is a modular application defined by a collection of options.
|
@@ -83,6 +112,7 @@ class Engin:
|
|
83
112
|
Args:
|
84
113
|
*options: an instance of Provide, Supply, Invoke, Entrypoint or a Block.
|
85
114
|
"""
|
115
|
+
self._state = _EnginState.IDLE
|
86
116
|
self._stop_requested_event = ShutdownSwitch()
|
87
117
|
self._stop_complete_event = Event()
|
88
118
|
self._exit_stack: AsyncExitStack = AsyncExitStack()
|
@@ -118,8 +148,13 @@ class Engin:
|
|
118
148
|
SIGINT), the `stop` method is called on the engin, or a lifecycle task errors.
|
119
149
|
"""
|
120
150
|
await self.start()
|
121
|
-
|
122
|
-
|
151
|
+
|
152
|
+
# engin failed to start, so exit early
|
153
|
+
if self._state != _EnginState.STARTED:
|
154
|
+
return
|
155
|
+
|
156
|
+
self._state = _EnginState.RUNNING
|
157
|
+
|
123
158
|
async with create_task_group() as tg:
|
124
159
|
tg.start_soon(_stop_engin_on_signal, self._stop_requested_event)
|
125
160
|
try:
|
@@ -137,6 +172,9 @@ class Engin:
|
|
137
172
|
lifecycle to complete and then returns. The caller is then responsible for
|
138
173
|
calling `stop`.
|
139
174
|
"""
|
175
|
+
if self._state != _EnginState.IDLE:
|
176
|
+
raise EnginError("Engin is not idle, unable to start")
|
177
|
+
|
140
178
|
LOG.info("starting engin")
|
141
179
|
assembled_invocations: list[AssembledDependency] = [
|
142
180
|
await self._assembler.assemble(invocation) for invocation in self._invocations
|
@@ -169,8 +207,7 @@ class Engin:
|
|
169
207
|
return
|
170
208
|
|
171
209
|
LOG.info("startup complete")
|
172
|
-
|
173
|
-
self._shutdown_task = asyncio.create_task(self._shutdown_when_stopped())
|
210
|
+
self._state = _EnginState.STARTED
|
174
211
|
|
175
212
|
async def stop(self) -> None:
|
176
213
|
"""
|
@@ -180,10 +217,13 @@ class Engin:
|
|
180
217
|
Note this method can be safely called at any point, even before the engin is
|
181
218
|
started.
|
182
219
|
"""
|
183
|
-
|
184
|
-
if self.
|
185
|
-
|
186
|
-
|
220
|
+
# If the Engin was ran via `start()` perform shutdown directly
|
221
|
+
if self._state == _EnginState.STARTED:
|
222
|
+
await self._shutdown()
|
223
|
+
# If the Engin was ran via `run()` notify via event
|
224
|
+
elif self._state == _EnginState.RUNNING:
|
225
|
+
self._stop_requested_event.set()
|
226
|
+
await self._stop_complete_event.wait()
|
187
227
|
|
188
228
|
def graph(self) -> list[Node]:
|
189
229
|
grapher = DependencyGrapher({**self._providers, **self._multiproviders})
|
@@ -194,10 +234,7 @@ class Engin:
|
|
194
234
|
await self._exit_stack.aclose()
|
195
235
|
self._stop_complete_event.set()
|
196
236
|
LOG.info("shutdown complete")
|
197
|
-
|
198
|
-
async def _shutdown_when_stopped(self) -> None:
|
199
|
-
await self._stop_requested_event.wait()
|
200
|
-
await self._shutdown()
|
237
|
+
self._state = _EnginState.SHUTDOWN
|
201
238
|
|
202
239
|
|
203
240
|
async def _stop_engin_on_signal(stop_requested_event: Event) -> None:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: engin
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.1.0a2
|
4
4
|
Summary: An async-first modular application framework
|
5
5
|
Project-URL: Homepage, https://github.com/invokermain/engin
|
6
6
|
Project-URL: Documentation, https://engin.readthedocs.io/en/latest/
|
@@ -20,7 +20,7 @@ Description-Content-Type: text/markdown
|
|
20
20
|
|
21
21
|
# Engin 🏎️
|
22
22
|
|
23
|
-
Engin is a
|
23
|
+
Engin is a lightweight application framework for modern Python.
|
24
24
|
|
25
25
|
**Documentation**: https://engin.readthedocs.io/
|
26
26
|
|
@@ -2,7 +2,7 @@ engin/__init__.py,sha256=v5OWwQoxTtqh2sB2E5iSMg3gATJoXKOuJLq28aZX6C8,642
|
|
2
2
|
engin/_assembler.py,sha256=-ENSrXPMWacionIYrTSQO7th9DDBOPyAT8ybPbBRtQw,11318
|
3
3
|
engin/_block.py,sha256=IacP4PoJKRhSQCbQSdoyCtmu362a4vj6qoUQKyaJwzI,3062
|
4
4
|
engin/_dependency.py,sha256=xINk3sudxzsTmkUkNAKQwzBc0G0DfhpnrZli4z3ALBY,9459
|
5
|
-
engin/_engin.py,sha256=
|
5
|
+
engin/_engin.py,sha256=XkGUG3D7z8X31rZhbu02_NFhFwSKB4JPSoma5jv6nq4,9135
|
6
6
|
engin/_graph.py,sha256=y1g7Lm_Zy5GPEgRsggCKV5DDaDzcwUl8v3IZCK8jyGI,1631
|
7
7
|
engin/_introspect.py,sha256=VdREX6Lhhga5SnEP9G7mjHkgJR4mpqk_SMnmL2zTcqY,966
|
8
8
|
engin/_lifecycle.py,sha256=cSWe3euZkmpxmUPFvph2lsTtvuZbxttEfBL-RnOI7lo,5325
|
@@ -20,8 +20,8 @@ engin/_cli/_inspect.py,sha256=0jm25d4wcbXVNJkyaeECSKY-irsxd-EIYBH1GDW_Yjc,3163
|
|
20
20
|
engin/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
21
21
|
engin/extensions/asgi.py,sha256=d5Z6gtMVWDZdAlvrTaMt987sKyiq__A0X4gJQ7IETmA,3247
|
22
22
|
engin/extensions/fastapi.py,sha256=7N6i-eZUEZRPo7kcvjS7kbRSY5QAPyKJXSeongSQ-OA,6371
|
23
|
-
engin-0.
|
24
|
-
engin-0.
|
25
|
-
engin-0.
|
26
|
-
engin-0.
|
27
|
-
engin-0.
|
23
|
+
engin-0.1.0a2.dist-info/METADATA,sha256=eg-rPpaGOV1MDNenGqSGCldPlTHh2yZ3CcZ0b5agakc,2408
|
24
|
+
engin-0.1.0a2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
25
|
+
engin-0.1.0a2.dist-info/entry_points.txt,sha256=sW247zZUMxm0b5UKYvPuqQQljYDtU-j2zK3cu7gHwM0,41
|
26
|
+
engin-0.1.0a2.dist-info/licenses/LICENSE,sha256=XHh5LPUPKZWTBqBv2xxN2RU7D59nHoiJGb5RIt8f45w,1070
|
27
|
+
engin-0.1.0a2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|