engin 0.1.0a2__tar.gz → 0.1.0b3__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 (106) hide show
  1. {engin-0.1.0a2 → engin-0.1.0b3}/CHANGELOG.md +4 -0
  2. engin-0.1.0b3/PKG-INFO +108 -0
  3. engin-0.1.0b3/README.md +90 -0
  4. {engin-0.1.0a2 → engin-0.1.0b3}/docs/concepts/engin.md +1 -1
  5. {engin-0.1.0a2 → engin-0.1.0b3}/docs/concepts/invocations.md +6 -6
  6. {engin-0.1.0a2 → engin-0.1.0b3}/docs/concepts/lifecycle.md +0 -2
  7. engin-0.1.0b3/docs/index.md +86 -0
  8. engin-0.1.0b3/docs/tutorial.md +15 -0
  9. {engin-0.1.0a2 → engin-0.1.0b3}/mkdocs.yaml +12 -8
  10. {engin-0.1.0a2 → engin-0.1.0b3}/pyproject.toml +1 -1
  11. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/__init__.py +0 -2
  12. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_assembler.py +7 -5
  13. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_engin.py +79 -88
  14. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_supervisor.py +9 -27
  15. {engin-0.1.0a2 → engin-0.1.0b3}/tests/acceptance/test_engin_signal_handling.py +8 -1
  16. {engin-0.1.0a2 → engin-0.1.0b3}/tests/acceptance/test_error_in_shutdown.py +2 -0
  17. {engin-0.1.0a2 → engin-0.1.0b3}/tests/acceptance/test_error_in_start_up.py +5 -5
  18. {engin-0.1.0a2 → engin-0.1.0b3}/tests/acceptance/test_error_in_supervised_task.py +10 -2
  19. engin-0.1.0b3/tests/conftest.py +0 -0
  20. {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_assembler.py +8 -6
  21. {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_supervisor.py +21 -23
  22. {engin-0.1.0a2 → engin-0.1.0b3}/uv.lock +97 -97
  23. engin-0.1.0a2/PKG-INFO +0 -73
  24. engin-0.1.0a2/README.md +0 -55
  25. engin-0.1.0a2/docs/getting-started.md +0 -7
  26. engin-0.1.0a2/docs/index.md +0 -21
  27. engin-0.1.0a2/src/engin/_shutdown.py +0 -4
  28. {engin-0.1.0a2 → engin-0.1.0b3}/.github/workflows/benchmark.yaml +0 -0
  29. {engin-0.1.0a2 → engin-0.1.0b3}/.github/workflows/check.yaml +0 -0
  30. {engin-0.1.0a2 → engin-0.1.0b3}/.github/workflows/publish.yaml +0 -0
  31. {engin-0.1.0a2 → engin-0.1.0b3}/.gitignore +0 -0
  32. {engin-0.1.0a2 → engin-0.1.0b3}/.readthedocs.yaml +0 -0
  33. {engin-0.1.0a2 → engin-0.1.0b3}/LICENSE +0 -0
  34. {engin-0.1.0a2 → engin-0.1.0b3}/docs/concepts/blocks.md +0 -0
  35. {engin-0.1.0a2 → engin-0.1.0b3}/docs/concepts/providers.md +0 -0
  36. /engin-0.1.0a2/examples/__init__.py → /engin-0.1.0b3/docs/concepts/supervisor.md +0 -0
  37. {engin-0.1.0a2/docs/guides → engin-0.1.0b3/docs/integrations}/fastapi-graph.png +0 -0
  38. {engin-0.1.0a2/docs/guides → engin-0.1.0b3/docs/integrations}/fastapi.md +0 -0
  39. {engin-0.1.0a2 → engin-0.1.0b3}/docs/js/readthedocs.js +0 -0
  40. {engin-0.1.0a2 → engin-0.1.0b3}/docs/overrides/main.html +0 -0
  41. {engin-0.1.0a2 → engin-0.1.0b3}/docs/reference.md +0 -0
  42. {engin-0.1.0a2/examples/asgi → engin-0.1.0b3/examples}/__init__.py +0 -0
  43. {engin-0.1.0a2/examples/asgi/common → engin-0.1.0b3/examples/asgi}/__init__.py +0 -0
  44. {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/app.py +0 -0
  45. {engin-0.1.0a2/examples/asgi/common/db → engin-0.1.0b3/examples/asgi/common}/__init__.py +0 -0
  46. {engin-0.1.0a2/examples/asgi/common/db/adapaters → engin-0.1.0b3/examples/asgi/common/db}/__init__.py +0 -0
  47. {engin-0.1.0a2/examples/asgi/common/starlette → engin-0.1.0b3/examples/asgi/common/db/adapaters}/__init__.py +0 -0
  48. {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/common/db/adapaters/memory.py +0 -0
  49. {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/common/db/block.py +0 -0
  50. {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/common/db/ports.py +0 -0
  51. {engin-0.1.0a2/examples/asgi/features → engin-0.1.0b3/examples/asgi/common/starlette}/__init__.py +0 -0
  52. {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/common/starlette/endpoint.py +0 -0
  53. {engin-0.1.0a2/examples/asgi/features/cats → engin-0.1.0b3/examples/asgi/features}/__init__.py +0 -0
  54. {engin-0.1.0a2/examples/asgi/features/cats/api → engin-0.1.0b3/examples/asgi/features/cats}/__init__.py +0 -0
  55. {engin-0.1.0a2/examples/fastapi → engin-0.1.0b3/examples/asgi/features/cats/api}/__init__.py +0 -0
  56. {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/features/cats/api/get.py +0 -0
  57. {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/features/cats/api/post.py +0 -0
  58. {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/features/cats/block.py +0 -0
  59. {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/features/cats/domain.py +0 -0
  60. {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/main.py +0 -0
  61. {engin-0.1.0a2/examples/fastapi/routes → engin-0.1.0b3/examples/fastapi}/__init__.py +0 -0
  62. {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/app.py +0 -0
  63. {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/main.py +0 -0
  64. {engin-0.1.0a2/examples/fastapi/routes/cats → engin-0.1.0b3/examples/fastapi/routes}/__init__.py +0 -0
  65. {engin-0.1.0a2/examples/fastapi/routes/cats/adapters → engin-0.1.0b3/examples/fastapi/routes/cats}/__init__.py +0 -0
  66. {engin-0.1.0a2/examples/simple → engin-0.1.0b3/examples/fastapi/routes/cats/adapters}/__init__.py +0 -0
  67. {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/routes/cats/adapters/repository.py +0 -0
  68. {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/routes/cats/api.py +0 -0
  69. {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/routes/cats/block.py +0 -0
  70. {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/routes/cats/domain.py +0 -0
  71. {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/routes/cats/ports.py +0 -0
  72. {engin-0.1.0a2/src/engin/extensions → engin-0.1.0b3/examples/simple}/__init__.py +0 -0
  73. {engin-0.1.0a2 → engin-0.1.0b3}/examples/simple/main.py +0 -0
  74. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_block.py +0 -0
  75. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_cli/__init__.py +0 -0
  76. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_cli/_common.py +0 -0
  77. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_cli/_graph.html +0 -0
  78. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_cli/_graph.py +0 -0
  79. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_cli/_inspect.py +0 -0
  80. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_dependency.py +0 -0
  81. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_graph.py +0 -0
  82. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_introspect.py +0 -0
  83. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_lifecycle.py +0 -0
  84. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_option.py +0 -0
  85. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_type_utils.py +0 -0
  86. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/exceptions.py +0 -0
  87. {engin-0.1.0a2/tests → engin-0.1.0b3/src/engin/extensions}/__init__.py +0 -0
  88. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/extensions/asgi.py +0 -0
  89. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/extensions/fastapi.py +0 -0
  90. {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/py.typed +0 -0
  91. {engin-0.1.0a2/tests/acceptance → engin-0.1.0b3/tests}/__init__.py +0 -0
  92. {engin-0.1.0a2/tests/benchmarks → engin-0.1.0b3/tests/acceptance}/__init__.py +0 -0
  93. {engin-0.1.0a2 → engin-0.1.0b3}/tests/acceptance/test_fastapi.py +0 -0
  94. {engin-0.1.0a2/tests/cli → engin-0.1.0b3/tests/benchmarks}/__init__.py +0 -0
  95. {engin-0.1.0a2 → engin-0.1.0b3}/tests/benchmarks/conftest.py +0 -0
  96. {engin-0.1.0a2 → engin-0.1.0b3}/tests/benchmarks/test_bench_assembler.py +0 -0
  97. /engin-0.1.0a2/tests/conftest.py → /engin-0.1.0b3/tests/cli/__init__.py +0 -0
  98. {engin-0.1.0a2 → engin-0.1.0b3}/tests/cli/test_graph.py +0 -0
  99. {engin-0.1.0a2 → engin-0.1.0b3}/tests/cli/test_inspect.py +0 -0
  100. {engin-0.1.0a2 → engin-0.1.0b3}/tests/deps.py +0 -0
  101. {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_block.py +0 -0
  102. {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_dependencies.py +0 -0
  103. {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_engin.py +0 -0
  104. {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_graph.py +0 -0
  105. {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_lifecycle.py +0 -0
  106. {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_type_id.py +0 -0
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
 
12
12
  - Supervisor class which can safely supervise long running tasks.
13
13
 
14
+ ### Changed
15
+
16
+ - `ASGIEngin.run()` now raises an error to prevent incorrect usage.
17
+
14
18
 
15
19
  ## [0.0.20] - 2025-06-18
16
20
 
engin-0.1.0b3/PKG-INFO ADDED
@@ -0,0 +1,108 @@
1
+ Metadata-Version: 2.4
2
+ Name: engin
3
+ Version: 0.1.0b3
4
+ Summary: An async-first modular application framework
5
+ Project-URL: Homepage, https://github.com/invokermain/engin
6
+ Project-URL: Documentation, https://engin.readthedocs.io/en/latest/
7
+ Project-URL: Repository, https://github.com/invokermain/engin.git
8
+ Project-URL: Changelog, https://github.com/invokermain/engin/blob/main/CHANGELOG.md
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: Application Framework,Dependency Injection
12
+ Requires-Python: >=3.10
13
+ Requires-Dist: anyio>=4
14
+ Requires-Dist: exceptiongroup>=1
15
+ Provides-Extra: cli
16
+ Requires-Dist: typer>=0.15; extra == 'cli'
17
+ Description-Content-Type: text/markdown
18
+
19
+ # Engin 🏎️
20
+
21
+ [![codecov](https://codecov.io/gh/invokermain/engin/graph/badge.svg?token=4PJOIMV6IB)](https://codecov.io/gh/invokermain/engin)
22
+
23
+ ---
24
+
25
+ **Documentation**: [https://engin.readthedocs.io/](https://engin.readthedocs.io/)
26
+
27
+ **Source Code**: [https://github.com/invokermain/engin](https://github.com/invokermain/engin)
28
+
29
+ ---
30
+
31
+ Engin is a lightweight application framework powered by dependency injection, it helps
32
+ you build and maintain large monoliths and many microservices.
33
+
34
+
35
+ ## Features
36
+
37
+ The Engin framework includes:
38
+
39
+ - A fully-featured dependency injection system.
40
+ - A robust application runtime with lifecycle hooks and supervised background tasks.
41
+ - Zero boiler-plate code reuse across multiple applications.
42
+ - Integrations for other frameworks such as FastAPI.
43
+ - Full async support.
44
+ - CLI commands to aid local development.
45
+
46
+
47
+ ## Installation
48
+
49
+ Engin is available on PyPI, install using your favourite dependency manager:
50
+
51
+ - `pip install engin`
52
+ - `poetry add engin`
53
+ - `uv add engin`
54
+
55
+ ## Example
56
+
57
+ A small example which shows some of the runtime features of Engin. This application
58
+ makes a http request and then performs a shutdown.
59
+
60
+ ```python
61
+ import asyncio
62
+ from httpx import AsyncClient
63
+ from engin import Engin, Invoke, Lifecycle, Provide, Supervisor
64
+
65
+
66
+ def httpx_client_factory(lifecycle: Lifecycle) -> AsyncClient:
67
+ # create our http client
68
+ client = AsyncClient()
69
+ # this will open and close the AsyncClient as part of the application's lifecycle
70
+ lifecycle.append(client)
71
+ return client
72
+
73
+
74
+ async def main(
75
+ httpx_client: AsyncClient,
76
+ supervisor: Supervisor,
77
+ ) -> None:
78
+ async def http_request():
79
+ await httpx_client.get("https://httpbin.org/get")
80
+ # one we've made the http request shutdown the application
81
+ raise asyncio.CancelledError("Forcing shutdown")
82
+
83
+ # supervise the http request as part of the application's lifecycle
84
+ supervisor.supervise(http_request)
85
+
86
+ # define our modular application
87
+ engin = Engin(Provide(httpx_client_factory), Invoke(main))
88
+
89
+ # run it!
90
+ asyncio.run(engin.run())
91
+ ```
92
+
93
+ With logs enabled this will output:
94
+
95
+ ```shell
96
+ INFO:engin:starting engin
97
+ INFO:engin:startup complete
98
+ INFO:httpx:HTTP Request: GET https://httpbin.org/get "HTTP/1.1 200 OK"
99
+ INFO:engin:stopping engin
100
+ INFO:engin:shutdown complete
101
+ ```
102
+
103
+ ## Inspiration
104
+
105
+ Engin is heavily inspired by [Uber's Fx framework for Go](https://github.com/uber-go/fx)
106
+ and the [Injector framework for Python](https://github.com/python-injector/injector).
107
+
108
+ They are both great projects, check them out.
@@ -0,0 +1,90 @@
1
+ # Engin 🏎️
2
+
3
+ [![codecov](https://codecov.io/gh/invokermain/engin/graph/badge.svg?token=4PJOIMV6IB)](https://codecov.io/gh/invokermain/engin)
4
+
5
+ ---
6
+
7
+ **Documentation**: [https://engin.readthedocs.io/](https://engin.readthedocs.io/)
8
+
9
+ **Source Code**: [https://github.com/invokermain/engin](https://github.com/invokermain/engin)
10
+
11
+ ---
12
+
13
+ Engin is a lightweight application framework powered by dependency injection, it helps
14
+ you build and maintain large monoliths and many microservices.
15
+
16
+
17
+ ## Features
18
+
19
+ The Engin framework includes:
20
+
21
+ - A fully-featured dependency injection system.
22
+ - A robust application runtime with lifecycle hooks and supervised background tasks.
23
+ - Zero boiler-plate code reuse across multiple applications.
24
+ - Integrations for other frameworks such as FastAPI.
25
+ - Full async support.
26
+ - CLI commands to aid local development.
27
+
28
+
29
+ ## Installation
30
+
31
+ Engin is available on PyPI, install using your favourite dependency manager:
32
+
33
+ - `pip install engin`
34
+ - `poetry add engin`
35
+ - `uv add engin`
36
+
37
+ ## Example
38
+
39
+ A small example which shows some of the runtime features of Engin. This application
40
+ makes a http request and then performs a shutdown.
41
+
42
+ ```python
43
+ import asyncio
44
+ from httpx import AsyncClient
45
+ from engin import Engin, Invoke, Lifecycle, Provide, Supervisor
46
+
47
+
48
+ def httpx_client_factory(lifecycle: Lifecycle) -> AsyncClient:
49
+ # create our http client
50
+ client = AsyncClient()
51
+ # this will open and close the AsyncClient as part of the application's lifecycle
52
+ lifecycle.append(client)
53
+ return client
54
+
55
+
56
+ async def main(
57
+ httpx_client: AsyncClient,
58
+ supervisor: Supervisor,
59
+ ) -> None:
60
+ async def http_request():
61
+ await httpx_client.get("https://httpbin.org/get")
62
+ # one we've made the http request shutdown the application
63
+ raise asyncio.CancelledError("Forcing shutdown")
64
+
65
+ # supervise the http request as part of the application's lifecycle
66
+ supervisor.supervise(http_request)
67
+
68
+ # define our modular application
69
+ engin = Engin(Provide(httpx_client_factory), Invoke(main))
70
+
71
+ # run it!
72
+ asyncio.run(engin.run())
73
+ ```
74
+
75
+ With logs enabled this will output:
76
+
77
+ ```shell
78
+ INFO:engin:starting engin
79
+ INFO:engin:startup complete
80
+ INFO:httpx:HTTP Request: GET https://httpbin.org/get "HTTP/1.1 200 OK"
81
+ INFO:engin:stopping engin
82
+ INFO:engin:shutdown complete
83
+ ```
84
+
85
+ ## Inspiration
86
+
87
+ Engin is heavily inspired by [Uber's Fx framework for Go](https://github.com/uber-go/fx)
88
+ and the [Injector framework for Python](https://github.com/python-injector/injector).
89
+
90
+ They are both great projects, check them out.
@@ -1,6 +1,6 @@
1
1
  # The Engin
2
2
 
3
- The Engin is a self-contained modular application.
3
+ The Engin is your self-contained modular application.
4
4
 
5
5
  When ran the Engin takes care of the complete application lifecycle:
6
6
 
@@ -1,19 +1,19 @@
1
1
  # Invocations
2
2
 
3
- Invocations define the behaviour of your application, therefore without any Invocations
3
+ Invocations define the behaviour of your application, without any Invocations
4
4
  your application will not do anything.
5
5
 
6
- Like providers invocations are functions that take one or more dependencies as parameters,
7
- and they should always return None as the return value will not used by the Engin.
6
+ Like providers, invocations are functions that take one or more dependencies as
7
+ parameters, but they should always return None as the return value will not used by Engin.
8
8
 
9
- As part of the Engin's startup, all declared invocations will be called sequentially in
10
- the order they were registered.
9
+ As part of the Engin's startup sequence, all declared invocations will be called
10
+ sequentially in the order they were registered.
11
11
 
12
12
  Invocations can be used to define behaviour in two ways.
13
13
 
14
14
  **Implicit: Provider Lifecycle**
15
15
 
16
- Invocations are always called therefore their dependencies are always assembled. This
16
+ Invocations are always called and therefore their dependencies are always assembled. This
17
17
  means that any providers with lifecycles will register their lifecycles with the
18
18
  application if directly or indirectly used by an invocation.
19
19
 
@@ -1,5 +1,3 @@
1
- from contextlib import asynccontextmanager
2
-
3
1
  # Lifecycle
4
2
 
5
3
  Certain types of object naturally have some form of startup and shutdown behaviour
@@ -0,0 +1,86 @@
1
+ # Engin 🏎️
2
+
3
+ Engin is a lightweight application framework powered by dependency injection, it helps
4
+ you build and maintain large monoliths and many microservices.
5
+
6
+
7
+ ## Features
8
+
9
+ The Engin framework includes:
10
+
11
+ - A fully-featured dependency injection system.
12
+ - A robust application runtime with lifecycle hooks and supervised background tasks.
13
+ - Zero boiler-plate code reuse across multiple applications.
14
+ - Integrations for other frameworks such as FastAPI.
15
+ - Full async support.
16
+ - CLI commands to aid local development.
17
+
18
+
19
+ ## Installation
20
+
21
+ === "uv"
22
+
23
+ ```shell
24
+ uv add engin
25
+ ```
26
+
27
+ === "poetry"
28
+
29
+ ```shell
30
+ poetry add engin
31
+ ```
32
+
33
+ === "pip"
34
+
35
+ ```shell
36
+ pip install engin
37
+ ```
38
+
39
+ ## Example
40
+
41
+ A small example which shows some of the runtime features of Engin. This application
42
+ makes a http request and then performs a shutdown.
43
+
44
+ ```python
45
+ import asyncio
46
+ from httpx import AsyncClient
47
+ from engin import Engin, Invoke, Lifecycle, Provide, ShutdownSwitch, Supervisor
48
+
49
+
50
+ def httpx_client_factory(lifecycle: Lifecycle) -> AsyncClient:
51
+ # create our http client
52
+ client = AsyncClient()
53
+ # this will open and close the AsyncClient as part of the application's lifecycle
54
+ lifecycle.append(client)
55
+ return client
56
+
57
+
58
+ async def main(
59
+ httpx_client: AsyncClient,
60
+ shutdown: ShutdownSwitch,
61
+ supervisor: Supervisor,
62
+ ) -> None:
63
+ async def http_request():
64
+ await httpx_client.get("https://httpbin.org/get")
65
+ # one we've made the http request shutdown the application
66
+ shutdown.set()
67
+
68
+ # supervise the http request as part of the application's lifecycle
69
+ supervisor.supervise(http_request)
70
+
71
+ # define our modular application
72
+ engin = Engin(Provide(httpx_client_factory), Invoke(main))
73
+
74
+ # run it!
75
+ asyncio.run(engin.run())
76
+ ```
77
+
78
+ With logs enabled this will output:
79
+
80
+ ```shell
81
+ INFO:engin:starting engin
82
+ INFO:engin:startup complete
83
+ INFO:httpx:HTTP Request: GET https://httpbin.org/get "HTTP/1.1 200 OK"
84
+ INFO:engin:stopping engin
85
+ INFO:engin:shutdown complete
86
+ ```
@@ -0,0 +1,15 @@
1
+ # Tutorial
2
+
3
+ In this tutorial we will build a small toy application from scratch.
4
+
5
+ Our application will publish random numbers to a Valkey stream, and then consume them and
6
+ update a running total.
7
+
8
+ ## 1. Create a Valkey client
9
+
10
+ ```python
11
+ from valkey import Valkey
12
+
13
+ def valkey_client() -> Valkey:
14
+ ...
15
+ ```
@@ -7,7 +7,7 @@ theme:
7
7
  custom_dir: 'docs/overrides'
8
8
  features:
9
9
  - navigation.instant
10
- - navigation.tabs
10
+ - content.code.copy
11
11
  palette:
12
12
  - scheme: 'default'
13
13
  media: '(prefers-color-scheme: light)'
@@ -27,15 +27,14 @@ edit_uri: ""
27
27
 
28
28
  nav:
29
29
  - Home: "index.md"
30
- - Getting Started: "getting-started.md"
31
30
  - Concepts:
32
31
  - Engin: "concepts/engin.md"
33
32
  - Providers: "concepts/providers.md"
34
33
  - Invocations: "concepts/invocations.md"
35
34
  - Lifecycle: "concepts/lifecycle.md"
36
35
  - Blocks: "concepts/blocks.md"
37
- - Guides:
38
- - FastAPI: "guides/fastapi.md"
36
+ - Integrations:
37
+ - FastAPI: "integrations/fastapi.md"
39
38
  - Reference: "reference.md"
40
39
 
41
40
  extra_javascript:
@@ -60,6 +59,7 @@ plugins:
60
59
  inventories:
61
60
  - url: https://docs.python.org/3/objects.inv
62
61
  domains: [py, std]
62
+ - search
63
63
 
64
64
  watch:
65
65
  - src
@@ -71,9 +71,13 @@ markdown_extensions:
71
71
  - pymdownx.blocks.caption
72
72
  - pymdownx.details
73
73
  - pymdownx.highlight:
74
- anchor_linenums: true
75
- line_spans: __span
76
- pygments_lang_class: true
74
+ anchor_linenums: true
75
+ line_spans: __span
76
+ pygments_lang_class: true
77
77
  - pymdownx.inlinehilite
78
- - pymdownx.snippets
78
+ - pymdownx.snippets:
79
+ base_path: [!relative $config_dir]
80
+ check_paths: true
79
81
  - pymdownx.superfences
82
+ - pymdownx.tabbed:
83
+ alternate_style: true
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "engin"
3
- version = "0.1.0a2"
3
+ version = "0.1.0b3"
4
4
  description = "An async-first modular application framework"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -4,7 +4,6 @@ from engin._dependency import Entrypoint, Invoke, Provide, Supply
4
4
  from engin._engin import Engin
5
5
  from engin._lifecycle import Lifecycle
6
6
  from engin._option import Option
7
- from engin._shutdown import ShutdownSwitch
8
7
  from engin._supervisor import OnException, Supervisor
9
8
  from engin._type_utils import TypeId
10
9
 
@@ -18,7 +17,6 @@ __all__ = [
18
17
  "OnException",
19
18
  "Option",
20
19
  "Provide",
21
- "ShutdownSwitch",
22
20
  "Supervisor",
23
21
  "Supply",
24
22
  "TypeId",
@@ -65,7 +65,7 @@ class Assembler:
65
65
  self._multiproviders: dict[TypeId, list[Provide[list[Any]]]] = defaultdict(list)
66
66
  self._assembled_outputs: dict[TypeId, Any] = {}
67
67
  self._lock = asyncio.Lock()
68
- self._graph_cache: dict[TypeId, set[Provide]] = defaultdict(set)
68
+ self._graph_cache: dict[TypeId, list[Provide]] = defaultdict(list)
69
69
 
70
70
  for provider in providers:
71
71
  type_id = provider.return_type_id
@@ -206,10 +206,10 @@ class Assembler:
206
206
  if provider.scope == scope:
207
207
  self._assembled_outputs.pop(type_id, None)
208
208
 
209
- def _resolve_providers(self, type_id: TypeId, resolved: set[TypeId]) -> set[Provide]:
209
+ def _resolve_providers(self, type_id: TypeId, resolved: set[TypeId]) -> Iterable[Provide]:
210
210
  """
211
211
  Resolves the chain of providers required to satisfy the provider of a given type.
212
- Ordering of the return value is very important!
212
+ Ordering of the return value is very important here!
213
213
  """
214
214
  if type_id in self._graph_cache:
215
215
  return self._graph_cache[type_id]
@@ -231,13 +231,15 @@ class Assembler:
231
231
  raise LookupError(msg)
232
232
 
233
233
  # providers that must be satisfied to satisfy the root level providers
234
- resolved_providers = {
234
+ resolved_providers = [
235
235
  child_provider
236
236
  for root_provider in root_providers
237
237
  for root_provider_param in root_provider.parameter_type_ids
238
238
  for child_provider in self._resolve_providers(root_provider_param, resolved)
239
239
  if root_provider_param not in resolved
240
- } | set(root_providers)
240
+ ]
241
+
242
+ resolved_providers.extend(root_providers)
241
243
 
242
244
  resolved.add(type_id)
243
245
  self._graph_cache[type_id] = resolved_providers