engin 0.1a1__tar.gz → 0.1.0a2__tar.gz

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.
Files changed (102) hide show
  1. {engin-0.1a1 → engin-0.1.0a2}/PKG-INFO +2 -2
  2. {engin-0.1a1 → engin-0.1.0a2}/README.md +1 -1
  3. {engin-0.1a1 → engin-0.1.0a2}/docs/index.md +1 -1
  4. {engin-0.1a1 → engin-0.1.0a2}/pyproject.toml +1 -1
  5. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_engin.py +49 -12
  6. engin-0.1.0a2/tests/acceptance/test_engin_signal_handling.py +17 -0
  7. {engin-0.1a1 → engin-0.1.0a2}/tests/acceptance/test_error_in_start_up.py +8 -0
  8. engin-0.1.0a2/tests/acceptance/test_error_in_supervised_task.py +21 -0
  9. {engin-0.1a1 → engin-0.1.0a2}/uv.lock +15 -14
  10. engin-0.1a1/tests/acceptance/test_error_in_supervised_task.py +0 -17
  11. {engin-0.1a1 → engin-0.1.0a2}/.github/workflows/benchmark.yaml +0 -0
  12. {engin-0.1a1 → engin-0.1.0a2}/.github/workflows/check.yaml +0 -0
  13. {engin-0.1a1 → engin-0.1.0a2}/.github/workflows/publish.yaml +0 -0
  14. {engin-0.1a1 → engin-0.1.0a2}/.gitignore +0 -0
  15. {engin-0.1a1 → engin-0.1.0a2}/.readthedocs.yaml +0 -0
  16. {engin-0.1a1 → engin-0.1.0a2}/CHANGELOG.md +0 -0
  17. {engin-0.1a1 → engin-0.1.0a2}/LICENSE +0 -0
  18. {engin-0.1a1 → engin-0.1.0a2}/docs/concepts/blocks.md +0 -0
  19. {engin-0.1a1 → engin-0.1.0a2}/docs/concepts/engin.md +0 -0
  20. {engin-0.1a1 → engin-0.1.0a2}/docs/concepts/invocations.md +0 -0
  21. {engin-0.1a1 → engin-0.1.0a2}/docs/concepts/lifecycle.md +0 -0
  22. {engin-0.1a1 → engin-0.1.0a2}/docs/concepts/providers.md +0 -0
  23. {engin-0.1a1 → engin-0.1.0a2}/docs/getting-started.md +0 -0
  24. {engin-0.1a1 → engin-0.1.0a2}/docs/guides/fastapi-graph.png +0 -0
  25. {engin-0.1a1 → engin-0.1.0a2}/docs/guides/fastapi.md +0 -0
  26. {engin-0.1a1 → engin-0.1.0a2}/docs/js/readthedocs.js +0 -0
  27. {engin-0.1a1 → engin-0.1.0a2}/docs/overrides/main.html +0 -0
  28. {engin-0.1a1 → engin-0.1.0a2}/docs/reference.md +0 -0
  29. {engin-0.1a1 → engin-0.1.0a2}/examples/__init__.py +0 -0
  30. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/__init__.py +0 -0
  31. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/app.py +0 -0
  32. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/common/__init__.py +0 -0
  33. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/common/db/__init__.py +0 -0
  34. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/common/db/adapaters/__init__.py +0 -0
  35. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/common/db/adapaters/memory.py +0 -0
  36. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/common/db/block.py +0 -0
  37. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/common/db/ports.py +0 -0
  38. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/common/starlette/__init__.py +0 -0
  39. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/common/starlette/endpoint.py +0 -0
  40. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/features/__init__.py +0 -0
  41. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/features/cats/__init__.py +0 -0
  42. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/features/cats/api/__init__.py +0 -0
  43. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/features/cats/api/get.py +0 -0
  44. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/features/cats/api/post.py +0 -0
  45. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/features/cats/block.py +0 -0
  46. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/features/cats/domain.py +0 -0
  47. {engin-0.1a1 → engin-0.1.0a2}/examples/asgi/main.py +0 -0
  48. {engin-0.1a1 → engin-0.1.0a2}/examples/fastapi/__init__.py +0 -0
  49. {engin-0.1a1 → engin-0.1.0a2}/examples/fastapi/app.py +0 -0
  50. {engin-0.1a1 → engin-0.1.0a2}/examples/fastapi/main.py +0 -0
  51. {engin-0.1a1 → engin-0.1.0a2}/examples/fastapi/routes/__init__.py +0 -0
  52. {engin-0.1a1 → engin-0.1.0a2}/examples/fastapi/routes/cats/__init__.py +0 -0
  53. {engin-0.1a1 → engin-0.1.0a2}/examples/fastapi/routes/cats/adapters/__init__.py +0 -0
  54. {engin-0.1a1 → engin-0.1.0a2}/examples/fastapi/routes/cats/adapters/repository.py +0 -0
  55. {engin-0.1a1 → engin-0.1.0a2}/examples/fastapi/routes/cats/api.py +0 -0
  56. {engin-0.1a1 → engin-0.1.0a2}/examples/fastapi/routes/cats/block.py +0 -0
  57. {engin-0.1a1 → engin-0.1.0a2}/examples/fastapi/routes/cats/domain.py +0 -0
  58. {engin-0.1a1 → engin-0.1.0a2}/examples/fastapi/routes/cats/ports.py +0 -0
  59. {engin-0.1a1 → engin-0.1.0a2}/examples/simple/__init__.py +0 -0
  60. {engin-0.1a1 → engin-0.1.0a2}/examples/simple/main.py +0 -0
  61. {engin-0.1a1 → engin-0.1.0a2}/mkdocs.yaml +0 -0
  62. {engin-0.1a1 → engin-0.1.0a2}/src/engin/__init__.py +0 -0
  63. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_assembler.py +0 -0
  64. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_block.py +0 -0
  65. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_cli/__init__.py +0 -0
  66. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_cli/_common.py +0 -0
  67. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_cli/_graph.html +0 -0
  68. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_cli/_graph.py +0 -0
  69. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_cli/_inspect.py +0 -0
  70. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_dependency.py +0 -0
  71. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_graph.py +0 -0
  72. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_introspect.py +0 -0
  73. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_lifecycle.py +0 -0
  74. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_option.py +0 -0
  75. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_shutdown.py +0 -0
  76. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_supervisor.py +0 -0
  77. {engin-0.1a1 → engin-0.1.0a2}/src/engin/_type_utils.py +0 -0
  78. {engin-0.1a1 → engin-0.1.0a2}/src/engin/exceptions.py +0 -0
  79. {engin-0.1a1 → engin-0.1.0a2}/src/engin/extensions/__init__.py +0 -0
  80. {engin-0.1a1 → engin-0.1.0a2}/src/engin/extensions/asgi.py +0 -0
  81. {engin-0.1a1 → engin-0.1.0a2}/src/engin/extensions/fastapi.py +0 -0
  82. {engin-0.1a1 → engin-0.1.0a2}/src/engin/py.typed +0 -0
  83. {engin-0.1a1 → engin-0.1.0a2}/tests/__init__.py +0 -0
  84. {engin-0.1a1 → engin-0.1.0a2}/tests/acceptance/__init__.py +0 -0
  85. {engin-0.1a1 → engin-0.1.0a2}/tests/acceptance/test_error_in_shutdown.py +0 -0
  86. {engin-0.1a1 → engin-0.1.0a2}/tests/acceptance/test_fastapi.py +0 -0
  87. {engin-0.1a1 → engin-0.1.0a2}/tests/benchmarks/__init__.py +0 -0
  88. {engin-0.1a1 → engin-0.1.0a2}/tests/benchmarks/conftest.py +0 -0
  89. {engin-0.1a1 → engin-0.1.0a2}/tests/benchmarks/test_bench_assembler.py +0 -0
  90. {engin-0.1a1 → engin-0.1.0a2}/tests/cli/__init__.py +0 -0
  91. {engin-0.1a1 → engin-0.1.0a2}/tests/cli/test_graph.py +0 -0
  92. {engin-0.1a1 → engin-0.1.0a2}/tests/cli/test_inspect.py +0 -0
  93. {engin-0.1a1 → engin-0.1.0a2}/tests/conftest.py +0 -0
  94. {engin-0.1a1 → engin-0.1.0a2}/tests/deps.py +0 -0
  95. {engin-0.1a1 → engin-0.1.0a2}/tests/test_assembler.py +0 -0
  96. {engin-0.1a1 → engin-0.1.0a2}/tests/test_block.py +0 -0
  97. {engin-0.1a1 → engin-0.1.0a2}/tests/test_dependencies.py +0 -0
  98. {engin-0.1a1 → engin-0.1.0a2}/tests/test_engin.py +0 -0
  99. {engin-0.1a1 → engin-0.1.0a2}/tests/test_graph.py +0 -0
  100. {engin-0.1a1 → engin-0.1.0a2}/tests/test_lifecycle.py +0 -0
  101. {engin-0.1a1 → engin-0.1.0a2}/tests/test_supervisor.py +0 -0
  102. {engin-0.1a1 → engin-0.1.0a2}/tests/test_type_id.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engin
3
- Version: 0.1a1
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 zero-dependency application framework for modern Python.
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 @@
2
2
 
3
3
  # Engin 🏎️
4
4
 
5
- Engin is a zero-dependency application framework for modern Python.
5
+ Engin is a lightweight application framework for modern Python.
6
6
 
7
7
  **Documentation**: https://engin.readthedocs.io/
8
8
 
@@ -1,6 +1,6 @@
1
1
  # Introduction
2
2
 
3
- Engin is a zero-dependency application framework for modern Python.
3
+ Engin is a lightweight application framework for modern Python.
4
4
 
5
5
  Engin is inspired by [Uber's Fx framework for Go](https://github.com/uber-go/fx) and the
6
6
  [Injector framework for Python](https://github.com/python-injector/injector).
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "engin"
3
- version = "0.1.a1"
3
+ version = "0.1.0a2"
4
4
  description = "An async-first modular application framework"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -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
- if self._shutdown_task:
122
- self._shutdown_task.cancel("redundant")
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
- self._stop_requested_event.set()
184
- if self._shutdown_task is None:
185
- return
186
- await self._stop_complete_event.wait()
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:
@@ -0,0 +1,17 @@
1
+ import asyncio
2
+ from asyncio import TaskGroup
3
+
4
+ from engin import Engin
5
+ from engin._engin import _EnginState
6
+
7
+
8
+ async def test_engin_signal_handling():
9
+ engin = Engin()
10
+
11
+ async with TaskGroup() as tg:
12
+ tg.create_task(engin.run())
13
+ # give it time to startup
14
+ await asyncio.sleep(0.1)
15
+ assert engin._state == _EnginState.RUNNING
16
+ await engin.stop()
17
+ assert engin._state == _EnginState.SHUTDOWN
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  from contextlib import asynccontextmanager
2
3
 
3
4
  from starlette.applications import Starlette
@@ -35,6 +36,13 @@ async def test_error_in_startup():
35
36
  assert not B_LIFECYCLE_STATE
36
37
 
37
38
 
39
+ async def test_error_in_startup_handled_when_run():
40
+ engin = Engin(Invoke(a), Invoke(b))
41
+
42
+ await asyncio.wait_for(engin.run(), timeout=0.5)
43
+ assert not B_LIFECYCLE_STATE
44
+
45
+
38
46
  async def test_error_in_startup_asgi():
39
47
  def asgi_type() -> ASGIType:
40
48
  return Starlette()
@@ -0,0 +1,21 @@
1
+ import asyncio
2
+
3
+ from engin import Engin, Invoke, Supervisor
4
+
5
+
6
+ async def delayed_error_task():
7
+ raise RuntimeError("Process errored")
8
+
9
+
10
+ def supervise(supervisor: Supervisor) -> None:
11
+ supervisor.supervise(delayed_error_task)
12
+
13
+
14
+ async def test_error_in_supervised_task_handled_when_run(caplog):
15
+ engin = Engin(Invoke(supervise))
16
+ await asyncio.wait_for(engin.run(), timeout=0.5)
17
+
18
+
19
+ async def test_error_in_supervised_task_handled_when_start(caplog):
20
+ engin = Engin(Invoke(supervise))
21
+ await asyncio.wait_for(engin.start(), timeout=0.5)
@@ -37,15 +37,16 @@ wheels = [
37
37
 
38
38
  [[package]]
39
39
  name = "backrefs"
40
- version = "5.8"
40
+ version = "5.9"
41
41
  source = { registry = "https://pypi.org/simple" }
42
- sdist = { url = "https://files.pythonhosted.org/packages/6c/46/caba1eb32fa5784428ab401a5487f73db4104590ecd939ed9daaf18b47e0/backrefs-5.8.tar.gz", hash = "sha256:2cab642a205ce966af3dd4b38ee36009b31fa9502a35fd61d59ccc116e40a6bd", size = 6773994, upload-time = "2025-02-25T18:15:32.003Z" }
42
+ sdist = { url = "https://files.pythonhosted.org/packages/eb/a7/312f673df6a79003279e1f55619abbe7daebbb87c17c976ddc0345c04c7b/backrefs-5.9.tar.gz", hash = "sha256:808548cb708d66b82ee231f962cb36faaf4f2baab032f2fbb783e9c2fdddaa59", size = 5765857, upload-time = "2025-06-22T19:34:13.97Z" }
43
43
  wheels = [
44
- { url = "https://files.pythonhosted.org/packages/bf/cb/d019ab87fe70e0fe3946196d50d6a4428623dc0c38a6669c8cae0320fbf3/backrefs-5.8-py310-none-any.whl", hash = "sha256:c67f6638a34a5b8730812f5101376f9d41dc38c43f1fdc35cb54700f6ed4465d", size = 380337, upload-time = "2025-02-25T16:53:14.607Z" },
45
- { url = "https://files.pythonhosted.org/packages/a9/86/abd17f50ee21b2248075cb6924c6e7f9d23b4925ca64ec660e869c2633f1/backrefs-5.8-py311-none-any.whl", hash = "sha256:2e1c15e4af0e12e45c8701bd5da0902d326b2e200cafcd25e49d9f06d44bb61b", size = 392142, upload-time = "2025-02-25T16:53:17.266Z" },
46
- { url = "https://files.pythonhosted.org/packages/b3/04/7b415bd75c8ab3268cc138c76fa648c19495fcc7d155508a0e62f3f82308/backrefs-5.8-py312-none-any.whl", hash = "sha256:bbef7169a33811080d67cdf1538c8289f76f0942ff971222a16034da88a73486", size = 398021, upload-time = "2025-02-25T16:53:26.378Z" },
47
- { url = "https://files.pythonhosted.org/packages/04/b8/60dcfb90eb03a06e883a92abbc2ab95c71f0d8c9dd0af76ab1d5ce0b1402/backrefs-5.8-py313-none-any.whl", hash = "sha256:e3a63b073867dbefd0536425f43db618578528e3896fb77be7141328642a1585", size = 399915, upload-time = "2025-02-25T16:53:28.167Z" },
48
- { url = "https://files.pythonhosted.org/packages/0c/37/fb6973edeb700f6e3d6ff222400602ab1830446c25c7b4676d8de93e65b8/backrefs-5.8-py39-none-any.whl", hash = "sha256:a66851e4533fb5b371aa0628e1fee1af05135616b86140c9d787a2ffdf4b8fdc", size = 380336, upload-time = "2025-02-25T16:53:29.858Z" },
44
+ { url = "https://files.pythonhosted.org/packages/19/4d/798dc1f30468134906575156c089c492cf79b5a5fd373f07fe26c4d046bf/backrefs-5.9-py310-none-any.whl", hash = "sha256:db8e8ba0e9de81fcd635f440deab5ae5f2591b54ac1ebe0550a2ca063488cd9f", size = 380267, upload-time = "2025-06-22T19:34:05.252Z" },
45
+ { url = "https://files.pythonhosted.org/packages/55/07/f0b3375bf0d06014e9787797e6b7cc02b38ac9ff9726ccfe834d94e9991e/backrefs-5.9-py311-none-any.whl", hash = "sha256:6907635edebbe9b2dc3de3a2befff44d74f30a4562adbb8b36f21252ea19c5cf", size = 392072, upload-time = "2025-06-22T19:34:06.743Z" },
46
+ { url = "https://files.pythonhosted.org/packages/9d/12/4f345407259dd60a0997107758ba3f221cf89a9b5a0f8ed5b961aef97253/backrefs-5.9-py312-none-any.whl", hash = "sha256:7fdf9771f63e6028d7fee7e0c497c81abda597ea45d6b8f89e8ad76994f5befa", size = 397947, upload-time = "2025-06-22T19:34:08.172Z" },
47
+ { url = "https://files.pythonhosted.org/packages/10/bf/fa31834dc27a7f05e5290eae47c82690edc3a7b37d58f7fb35a1bdbf355b/backrefs-5.9-py313-none-any.whl", hash = "sha256:cc37b19fa219e93ff825ed1fed8879e47b4d89aa7a1884860e2db64ccd7c676b", size = 399843, upload-time = "2025-06-22T19:34:09.68Z" },
48
+ { url = "https://files.pythonhosted.org/packages/fc/24/b29af34b2c9c41645a9f4ff117bae860291780d73880f449e0b5d948c070/backrefs-5.9-py314-none-any.whl", hash = "sha256:df5e169836cc8acb5e440ebae9aad4bf9d15e226d3bad049cf3f6a5c20cc8dc9", size = 411762, upload-time = "2025-06-22T19:34:11.037Z" },
49
+ { url = "https://files.pythonhosted.org/packages/41/ff/392bff89415399a979be4a65357a41d92729ae8580a66073d8ec8d810f98/backrefs-5.9-py39-none-any.whl", hash = "sha256:f48ee18f6252b8f5777a22a00a09a85de0ca931658f1dd96d4406a34f3748c60", size = 380265, upload-time = "2025-06-22T19:34:12.405Z" },
49
50
  ]
50
51
 
51
52
  [[package]]
@@ -210,7 +211,7 @@ toml = [
210
211
 
211
212
  [[package]]
212
213
  name = "engin"
213
- version = "0.0.20"
214
+ version = "0.1a1"
214
215
  source = { editable = "." }
215
216
  dependencies = [
216
217
  { name = "anyio" },
@@ -841,16 +842,16 @@ wheels = [
841
842
 
842
843
  [[package]]
843
844
  name = "pydantic-settings"
844
- version = "2.10.0"
845
+ version = "2.10.1"
845
846
  source = { registry = "https://pypi.org/simple" }
846
847
  dependencies = [
847
848
  { name = "pydantic" },
848
849
  { name = "python-dotenv" },
849
850
  { name = "typing-inspection" },
850
851
  ]
851
- sdist = { url = "https://files.pythonhosted.org/packages/c2/ef/3d61472b7801c896f9efd9bb8750977d9577098b05224c5c41820690155e/pydantic_settings-2.10.0.tar.gz", hash = "sha256:7a12e0767ba283954f3fd3fefdd0df3af21b28aa849c40c35811d52d682fa876", size = 172625, upload-time = "2025-06-21T13:56:55.898Z" }
852
+ sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583, upload-time = "2025-06-24T13:26:46.841Z" }
852
853
  wheels = [
853
- { url = "https://files.pythonhosted.org/packages/7d/9e/fce9331fecf1d2761ff0516c5dceab8a5fd415e82943e727dc4c5fa84a90/pydantic_settings-2.10.0-py3-none-any.whl", hash = "sha256:33781dfa1c7405d5ed2b6f150830a93bb58462a847357bd8f162f8bacb77c027", size = 45232, upload-time = "2025-06-21T13:56:53.682Z" },
854
+ { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235, upload-time = "2025-06-24T13:26:45.485Z" },
854
855
  ]
855
856
 
856
857
  [[package]]
@@ -958,11 +959,11 @@ wheels = [
958
959
 
959
960
  [[package]]
960
961
  name = "python-dotenv"
961
- version = "1.1.0"
962
+ version = "1.1.1"
962
963
  source = { registry = "https://pypi.org/simple" }
963
- sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920, upload-time = "2025-03-25T10:14:56.835Z" }
964
+ sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" }
964
965
  wheels = [
965
- { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256, upload-time = "2025-03-25T10:14:55.034Z" },
966
+ { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" },
966
967
  ]
967
968
 
968
969
  [[package]]
@@ -1,17 +0,0 @@
1
- import asyncio
2
-
3
- from engin import Engin, Invoke, Supervisor
4
-
5
-
6
- async def delayed_error_task():
7
- await asyncio.sleep(0.5)
8
- raise RuntimeError("Process errored")
9
-
10
-
11
- def supervise(supervisor: Supervisor) -> None:
12
- supervisor.supervise(delayed_error_task)
13
-
14
-
15
- async def test_error_in_task(caplog):
16
- engin = Engin(Invoke(supervise))
17
- await engin.run()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes