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.
- {engin-0.1.0a2 → engin-0.1.0b3}/CHANGELOG.md +4 -0
- engin-0.1.0b3/PKG-INFO +108 -0
- engin-0.1.0b3/README.md +90 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/docs/concepts/engin.md +1 -1
- {engin-0.1.0a2 → engin-0.1.0b3}/docs/concepts/invocations.md +6 -6
- {engin-0.1.0a2 → engin-0.1.0b3}/docs/concepts/lifecycle.md +0 -2
- engin-0.1.0b3/docs/index.md +86 -0
- engin-0.1.0b3/docs/tutorial.md +15 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/mkdocs.yaml +12 -8
- {engin-0.1.0a2 → engin-0.1.0b3}/pyproject.toml +1 -1
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/__init__.py +0 -2
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_assembler.py +7 -5
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_engin.py +79 -88
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_supervisor.py +9 -27
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/acceptance/test_engin_signal_handling.py +8 -1
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/acceptance/test_error_in_shutdown.py +2 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/acceptance/test_error_in_start_up.py +5 -5
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/acceptance/test_error_in_supervised_task.py +10 -2
- engin-0.1.0b3/tests/conftest.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_assembler.py +8 -6
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_supervisor.py +21 -23
- {engin-0.1.0a2 → engin-0.1.0b3}/uv.lock +97 -97
- engin-0.1.0a2/PKG-INFO +0 -73
- engin-0.1.0a2/README.md +0 -55
- engin-0.1.0a2/docs/getting-started.md +0 -7
- engin-0.1.0a2/docs/index.md +0 -21
- engin-0.1.0a2/src/engin/_shutdown.py +0 -4
- {engin-0.1.0a2 → engin-0.1.0b3}/.github/workflows/benchmark.yaml +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/.github/workflows/check.yaml +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/.github/workflows/publish.yaml +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/.gitignore +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/.readthedocs.yaml +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/LICENSE +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/docs/concepts/blocks.md +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/docs/concepts/providers.md +0 -0
- /engin-0.1.0a2/examples/__init__.py → /engin-0.1.0b3/docs/concepts/supervisor.md +0 -0
- {engin-0.1.0a2/docs/guides → engin-0.1.0b3/docs/integrations}/fastapi-graph.png +0 -0
- {engin-0.1.0a2/docs/guides → engin-0.1.0b3/docs/integrations}/fastapi.md +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/docs/js/readthedocs.js +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/docs/overrides/main.html +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/docs/reference.md +0 -0
- {engin-0.1.0a2/examples/asgi → engin-0.1.0b3/examples}/__init__.py +0 -0
- {engin-0.1.0a2/examples/asgi/common → engin-0.1.0b3/examples/asgi}/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/app.py +0 -0
- {engin-0.1.0a2/examples/asgi/common/db → engin-0.1.0b3/examples/asgi/common}/__init__.py +0 -0
- {engin-0.1.0a2/examples/asgi/common/db/adapaters → engin-0.1.0b3/examples/asgi/common/db}/__init__.py +0 -0
- {engin-0.1.0a2/examples/asgi/common/starlette → engin-0.1.0b3/examples/asgi/common/db/adapaters}/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/common/db/adapaters/memory.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/common/db/block.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/common/db/ports.py +0 -0
- {engin-0.1.0a2/examples/asgi/features → engin-0.1.0b3/examples/asgi/common/starlette}/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/common/starlette/endpoint.py +0 -0
- {engin-0.1.0a2/examples/asgi/features/cats → engin-0.1.0b3/examples/asgi/features}/__init__.py +0 -0
- {engin-0.1.0a2/examples/asgi/features/cats/api → engin-0.1.0b3/examples/asgi/features/cats}/__init__.py +0 -0
- {engin-0.1.0a2/examples/fastapi → engin-0.1.0b3/examples/asgi/features/cats/api}/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/features/cats/api/get.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/features/cats/api/post.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/features/cats/block.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/features/cats/domain.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/asgi/main.py +0 -0
- {engin-0.1.0a2/examples/fastapi/routes → engin-0.1.0b3/examples/fastapi}/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/app.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/main.py +0 -0
- {engin-0.1.0a2/examples/fastapi/routes/cats → engin-0.1.0b3/examples/fastapi/routes}/__init__.py +0 -0
- {engin-0.1.0a2/examples/fastapi/routes/cats/adapters → engin-0.1.0b3/examples/fastapi/routes/cats}/__init__.py +0 -0
- {engin-0.1.0a2/examples/simple → engin-0.1.0b3/examples/fastapi/routes/cats/adapters}/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/routes/cats/adapters/repository.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/routes/cats/api.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/routes/cats/block.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/routes/cats/domain.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/fastapi/routes/cats/ports.py +0 -0
- {engin-0.1.0a2/src/engin/extensions → engin-0.1.0b3/examples/simple}/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/examples/simple/main.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_block.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_cli/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_cli/_common.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_cli/_graph.html +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_cli/_graph.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_cli/_inspect.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_dependency.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_graph.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_introspect.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_lifecycle.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_option.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/_type_utils.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/exceptions.py +0 -0
- {engin-0.1.0a2/tests → engin-0.1.0b3/src/engin/extensions}/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/extensions/asgi.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/extensions/fastapi.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/src/engin/py.typed +0 -0
- {engin-0.1.0a2/tests/acceptance → engin-0.1.0b3/tests}/__init__.py +0 -0
- {engin-0.1.0a2/tests/benchmarks → engin-0.1.0b3/tests/acceptance}/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/acceptance/test_fastapi.py +0 -0
- {engin-0.1.0a2/tests/cli → engin-0.1.0b3/tests/benchmarks}/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/benchmarks/conftest.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/benchmarks/test_bench_assembler.py +0 -0
- /engin-0.1.0a2/tests/conftest.py → /engin-0.1.0b3/tests/cli/__init__.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/cli/test_graph.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/cli/test_inspect.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/deps.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_block.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_dependencies.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_engin.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_graph.py +0 -0
- {engin-0.1.0a2 → engin-0.1.0b3}/tests/test_lifecycle.py +0 -0
- {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
|
+
[](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.
|
engin-0.1.0b3/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Engin 🏎️
|
2
|
+
|
3
|
+
[](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,19 +1,19 @@
|
|
1
1
|
# Invocations
|
2
2
|
|
3
|
-
Invocations define the behaviour of your application,
|
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
|
7
|
-
|
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
|
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
|
|
@@ -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
|
-
-
|
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
|
-
-
|
38
|
-
- FastAPI: "
|
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
|
-
|
75
|
-
|
76
|
-
|
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
|
@@ -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,
|
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]) ->
|
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
|
-
|
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
|