engin 0.1.0rc1__py3-none-any.whl → 0.1.0rc2__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/_assembler.py +5 -7
- engin/_cli/_check.py +2 -10
- engin/_cli/_graph.html +878 -73
- engin/_cli/_graph.py +122 -63
- engin/_cli/_inspect.py +6 -3
- engin/_engin.py +2 -2
- engin/_supervisor.py +17 -3
- engin/exceptions.py +21 -6
- {engin-0.1.0rc1.dist-info → engin-0.1.0rc2.dist-info}/METADATA +28 -15
- {engin-0.1.0rc1.dist-info → engin-0.1.0rc2.dist-info}/RECORD +13 -13
- {engin-0.1.0rc1.dist-info → engin-0.1.0rc2.dist-info}/WHEEL +0 -0
- {engin-0.1.0rc1.dist-info → engin-0.1.0rc2.dist-info}/entry_points.txt +0 -0
- {engin-0.1.0rc1.dist-info → engin-0.1.0rc2.dist-info}/licenses/LICENSE +0 -0
engin/_cli/_graph.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import contextlib
|
2
|
+
import json
|
2
3
|
import socketserver
|
3
4
|
import threading
|
4
5
|
from http.server import BaseHTTPRequestHandler
|
@@ -9,9 +10,10 @@ from typing import Annotated, Any
|
|
9
10
|
import typer
|
10
11
|
from rich import print
|
11
12
|
|
12
|
-
from engin import Entrypoint, Invoke, TypeId
|
13
|
+
from engin import Engin, Entrypoint, Invoke, TypeId
|
13
14
|
from engin._cli._common import COMMON_HELP, get_engin_instance
|
14
15
|
from engin._dependency import Dependency, Provide, Supply
|
16
|
+
from engin._graph import Node
|
15
17
|
from engin.extensions.asgi import ASGIEngin
|
16
18
|
|
17
19
|
try:
|
@@ -46,37 +48,11 @@ def serve_graph(
|
|
46
48
|
|
47
49
|
nodes = instance.graph()
|
48
50
|
|
49
|
-
#
|
50
|
-
|
51
|
-
f"{_render_node(node.parent)} --> {_render_node(node.node)}"
|
52
|
-
for node in nodes
|
53
|
-
if node.parent is not None
|
54
|
-
and not (node.node.block_name and node.node.block_name == node.parent.block_name)
|
55
|
-
]
|
51
|
+
# Generate JSON data for interactive graph
|
52
|
+
graph_data = _generate_graph_data(nodes, instance)
|
56
53
|
|
57
|
-
|
58
|
-
|
59
|
-
# group blocks into subgraphs
|
60
|
-
for block in blocks:
|
61
|
-
dependencies.append(f"subgraph {block}")
|
62
|
-
dependencies.extend(
|
63
|
-
[
|
64
|
-
f"{_render_node(node.parent, False)} --> {_render_node(node.node, False)}"
|
65
|
-
for node in nodes
|
66
|
-
if node.parent is not None
|
67
|
-
and node.node.block_name == block
|
68
|
-
and node.parent.block_name == block
|
69
|
-
]
|
70
|
-
)
|
71
|
-
dependencies.append("end")
|
72
|
-
|
73
|
-
html = (
|
74
|
-
_GRAPH_HTML.replace("%%DATA%%", "\n".join(dependencies))
|
75
|
-
.replace(
|
76
|
-
"%%LEGEND%%",
|
77
|
-
ASGI_ENGIN_LEGEND if isinstance(instance, ASGIEngin) else DEFAULT_LEGEND,
|
78
|
-
)
|
79
|
-
.encode("utf8")
|
54
|
+
html = _GRAPH_HTML.replace("%%GRAPH_DATA%%", json.dumps(graph_data, indent=2)).encode(
|
55
|
+
"utf8"
|
80
56
|
)
|
81
57
|
|
82
58
|
class Handler(BaseHTTPRequestHandler):
|
@@ -108,47 +84,130 @@ def wait_for_interrupt() -> None:
|
|
108
84
|
sleep(10000)
|
109
85
|
|
110
86
|
|
111
|
-
|
112
|
-
|
87
|
+
def _generate_graph_data(nodes: list[Node], instance: Engin) -> dict[str, Any]:
|
88
|
+
"""Generate JSON data structure for interactive graph rendering."""
|
89
|
+
all_deps = set()
|
90
|
+
for node in nodes:
|
91
|
+
all_deps.add(node.node)
|
92
|
+
if node.parent:
|
93
|
+
all_deps.add(node.parent)
|
94
|
+
|
95
|
+
# Generate node data
|
96
|
+
node_data = []
|
97
|
+
for dep in all_deps:
|
98
|
+
node_info = _get_node_info(dep)
|
99
|
+
node_data.append(node_info)
|
100
|
+
|
101
|
+
# Generate edge data
|
102
|
+
edge_data = [
|
103
|
+
{
|
104
|
+
"from": f"n{id(node.parent)}",
|
105
|
+
"to": f"n{id(node.node)}",
|
106
|
+
"from_block": node.parent.block_name,
|
107
|
+
"to_block": node.node.block_name,
|
108
|
+
}
|
109
|
+
for node in nodes
|
110
|
+
if node.parent is not None
|
111
|
+
]
|
113
112
|
|
113
|
+
# Get block information
|
114
|
+
blocks = list({node.node.block_name for node in nodes if node.node.block_name is not None})
|
114
115
|
|
115
|
-
|
116
|
-
|
117
|
-
md = ""
|
118
|
-
style = ""
|
116
|
+
# Generate legend
|
117
|
+
legend = ASGI_ENGIN_LEGEND if isinstance(instance, ASGIEngin) else DEFAULT_LEGEND
|
119
118
|
|
120
|
-
|
121
|
-
|
122
|
-
|
119
|
+
return {
|
120
|
+
"nodes": node_data,
|
121
|
+
"edges": edge_data,
|
122
|
+
"blocks": blocks,
|
123
|
+
"legend": legend,
|
124
|
+
"app_origin": _APP_ORIGIN,
|
125
|
+
}
|
123
126
|
|
124
|
-
node_root_package = node.source_package.split(".", maxsplit=1)[0]
|
125
|
-
if node_root_package != _APP_ORIGIN:
|
126
|
-
if style:
|
127
|
-
style += "E"
|
128
|
-
else:
|
129
|
-
style = "external"
|
130
127
|
|
131
|
-
|
132
|
-
|
128
|
+
def _get_node_info(node: Dependency) -> dict[str, Any]:
|
129
|
+
"""Extract node information for JSON representation."""
|
130
|
+
node_id = f"n{id(node)}" # Add 'n' prefix to match mermaid node IDs
|
131
|
+
label = ""
|
132
|
+
style_classes = []
|
133
133
|
|
134
|
+
# Determine if external
|
135
|
+
node_root_package = node.source_package.split(".", maxsplit=1)[0]
|
136
|
+
is_external = node_root_package != _APP_ORIGIN
|
137
|
+
if is_external:
|
138
|
+
style_classes.append("external")
|
139
|
+
|
140
|
+
# Collect detailed information for tooltips
|
141
|
+
details: dict[str, Any] = {
|
142
|
+
"full_name": node.name,
|
143
|
+
"source_module": node.source_module,
|
144
|
+
"source_package": node.source_package,
|
145
|
+
"parameters": [],
|
146
|
+
"return_type": None,
|
147
|
+
"scope": None,
|
148
|
+
}
|
149
|
+
|
150
|
+
# Get parameter information
|
151
|
+
if hasattr(node, "parameter_type_ids"):
|
152
|
+
details["parameters"] = [str(param_id) for param_id in node.parameter_type_ids]
|
153
|
+
|
154
|
+
# Determine node type and extract specific details
|
134
155
|
if isinstance(node, Supply):
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
156
|
+
node_type = "Supply"
|
157
|
+
label += f"{_short_name(node.return_type_id)}"
|
158
|
+
shape = "round"
|
159
|
+
details["return_type"] = str(node.return_type_id)
|
160
|
+
if hasattr(node, "_value"):
|
161
|
+
details["value_type"] = type(node._value).__name__
|
162
|
+
elif isinstance(node, Provide):
|
163
|
+
node_type = "Provide"
|
164
|
+
label += f"{_short_name(node.return_type_id)}"
|
165
|
+
shape = "rect"
|
166
|
+
details["return_type"] = str(node.return_type_id)
|
167
|
+
details["factory_function"] = node.func_name
|
168
|
+
if node.scope:
|
169
|
+
details["scope"] = node.scope
|
170
|
+
style_classes.append(f"scope-{node.scope}")
|
171
|
+
if node.is_multiprovider:
|
172
|
+
details["multiprovider"] = True
|
173
|
+
style_classes.append("multi")
|
174
|
+
elif isinstance(node, Entrypoint):
|
175
|
+
node_type = "Entrypoint"
|
141
176
|
entrypoint_type = node.parameter_type_ids[0]
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
177
|
+
label += f"{entrypoint_type}"
|
178
|
+
shape = "trapezoid"
|
179
|
+
details["entrypoint_type"] = str(entrypoint_type)
|
180
|
+
elif isinstance(node, Invoke):
|
181
|
+
node_type = "Invoke"
|
182
|
+
label += f"{node.func_name}"
|
183
|
+
shape = "trapezoid"
|
184
|
+
details["function"] = node.func_name
|
185
|
+
elif APIRouteDependency is not None and isinstance(node, APIRouteDependency):
|
186
|
+
node_type = "APIRoute"
|
187
|
+
label += f"{node.name}"
|
188
|
+
shape = "subroutine"
|
189
|
+
if hasattr(node, "route"):
|
190
|
+
details["methods"] = (
|
191
|
+
list(node.route.methods) if hasattr(node.route, "methods") else []
|
192
|
+
)
|
193
|
+
details["path"] = getattr(node.route, "path", "")
|
150
194
|
else:
|
151
|
-
|
195
|
+
node_type = "Other"
|
196
|
+
label += f"{node.name}"
|
197
|
+
shape = "rect"
|
198
|
+
|
199
|
+
return {
|
200
|
+
"id": node_id,
|
201
|
+
"label": label,
|
202
|
+
"type": node_type,
|
203
|
+
"external": is_external,
|
204
|
+
"block": node.block_name,
|
205
|
+
"shape": shape,
|
206
|
+
"style_classes": style_classes,
|
207
|
+
"source_module": node.source_module,
|
208
|
+
"source_package": node.source_package,
|
209
|
+
"details": details,
|
210
|
+
}
|
152
211
|
|
153
212
|
|
154
213
|
def _short_name(name: TypeId) -> str:
|
engin/_cli/_inspect.py
CHANGED
@@ -11,7 +11,7 @@ from engin._cli._common import COMMON_HELP, get_engin_instance, print_error
|
|
11
11
|
cli = typer.Typer()
|
12
12
|
_CLI_HELP = {
|
13
13
|
"type": "Filter providers by the provided type, e.g. `AsyncClient` or `float[]`",
|
14
|
-
"module": "Filter providers by the provided
|
14
|
+
"module": "Filter providers by the provided type's module, e.g. `engin` or `httpx`",
|
15
15
|
"verbose": "Enables verbose output",
|
16
16
|
}
|
17
17
|
|
@@ -74,8 +74,11 @@ def serve_graph(
|
|
74
74
|
available = sorted(map(str, instance.assembler.providers))
|
75
75
|
print_error(f"No matching providers, available: {available}")
|
76
76
|
|
77
|
-
|
78
|
-
|
77
|
+
console.print(
|
78
|
+
f"Found {matching_provider_count} matching provider"
|
79
|
+
+ ("s" if matching_provider_count > 1 else ""),
|
80
|
+
style="dim",
|
81
|
+
)
|
79
82
|
|
80
83
|
table = Table(show_header=False, show_lines=False, box=box.ASCII)
|
81
84
|
|
engin/_engin.py
CHANGED
@@ -61,8 +61,8 @@ class Engin:
|
|
61
61
|
the Invoke options parameters are assembled.
|
62
62
|
2. All Invocations are run sequentially in the order they were passed in to the Engin.
|
63
63
|
3. Lifecycle Startup tasks registered by assembled dependencies are run sequentially.
|
64
|
-
4. The Engin waits for a stop signal, i.e. SIGINT or SIGTERM, or
|
65
|
-
|
64
|
+
4. The Engin waits for a stop signal, i.e. SIGINT or SIGTERM, or a supervised task that
|
65
|
+
causes a shutdown.
|
66
66
|
5. Lifecyce Shutdown tasks are run in the reverse order to the Startup order.
|
67
67
|
|
68
68
|
Examples:
|
engin/_supervisor.py
CHANGED
@@ -58,19 +58,33 @@ class _SupervisorTask:
|
|
58
58
|
await self.factory()
|
59
59
|
self.complete = True
|
60
60
|
return
|
61
|
-
except get_cancelled_exc_class():
|
62
|
-
LOG.
|
61
|
+
except get_cancelled_exc_class() as err:
|
62
|
+
LOG.debug(f"supervised task '{self.name}' was cancelled", exc_info=err)
|
63
63
|
raise
|
64
64
|
except Exception as err:
|
65
|
-
LOG.error(f"Supervisor: {self.name} raised {type(err).__name__}", exc_info=err)
|
66
65
|
self.last_exception = err
|
67
66
|
|
68
67
|
if self.on_exception == OnException.IGNORE:
|
68
|
+
LOG.warning(
|
69
|
+
f"supervisor task '{self.name}' raised {type(err).__name__} "
|
70
|
+
"which will be ignored",
|
71
|
+
exc_info=err,
|
72
|
+
)
|
69
73
|
self.complete = True
|
70
74
|
return
|
71
75
|
if self.on_exception == OnException.RETRY:
|
76
|
+
LOG.warning(
|
77
|
+
f"supervisor task '{self.name}' raised {type(err).__name__} "
|
78
|
+
"which will be retried",
|
79
|
+
exc_info=err,
|
80
|
+
)
|
72
81
|
continue
|
73
82
|
if self.on_exception == OnException.SHUTDOWN:
|
83
|
+
LOG.error(
|
84
|
+
f"supervisor task '{self.name}' raised {type(err).__name__}, "
|
85
|
+
"starting shutdown",
|
86
|
+
exc_info=err,
|
87
|
+
)
|
74
88
|
self.complete = True
|
75
89
|
raise get_cancelled_exc_class() from None
|
76
90
|
assert_never(self.on_exception)
|
engin/exceptions.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from typing import TYPE_CHECKING, Any
|
2
2
|
|
3
3
|
from engin._dependency import Provide
|
4
|
+
from engin._type_utils import TypeId
|
4
5
|
|
5
6
|
if TYPE_CHECKING:
|
6
7
|
from engin._block import Block
|
@@ -12,12 +13,6 @@ class EnginError(Exception):
|
|
12
13
|
"""
|
13
14
|
|
14
15
|
|
15
|
-
class AssemblerError(EnginError):
|
16
|
-
"""
|
17
|
-
Base class for all custom exceptions raised by the Assembler.
|
18
|
-
"""
|
19
|
-
|
20
|
-
|
21
16
|
class InvalidBlockError(EnginError):
|
22
17
|
"""
|
23
18
|
Raised when an invalid block is instantiated.
|
@@ -32,6 +27,25 @@ class InvalidBlockError(EnginError):
|
|
32
27
|
return self.message
|
33
28
|
|
34
29
|
|
30
|
+
class AssemblerError(EnginError):
|
31
|
+
"""
|
32
|
+
Base class for all custom exceptions raised by the Assembler.
|
33
|
+
"""
|
34
|
+
|
35
|
+
|
36
|
+
class TypeNotProvidedError(AssemblerError):
|
37
|
+
"""
|
38
|
+
Raised when the Assembler cannot assemble a type due to a missing Provider.
|
39
|
+
"""
|
40
|
+
|
41
|
+
def __init__(self, type_id: TypeId) -> None:
|
42
|
+
self.type_id = type_id
|
43
|
+
self.message = f"no provider found for '{type_id}'"
|
44
|
+
|
45
|
+
def __str__(self) -> str:
|
46
|
+
return self.message
|
47
|
+
|
48
|
+
|
35
49
|
class ProviderError(AssemblerError):
|
36
50
|
"""
|
37
51
|
Raised when a Provider errors during Assembly.
|
@@ -77,4 +91,5 @@ __all__ = [
|
|
77
91
|
"InvalidBlockError",
|
78
92
|
"NotInScopeError",
|
79
93
|
"ProviderError",
|
94
|
+
"TypeNotProvidedError",
|
80
95
|
]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: engin
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.0rc2
|
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/
|
@@ -33,13 +33,13 @@ Engin is a lightweight application framework powered by dependency injection, it
|
|
33
33
|
you build and maintain large monoliths and many microservices.
|
34
34
|
|
35
35
|
|
36
|
-
##
|
36
|
+
## Feature
|
37
37
|
|
38
|
-
The Engin framework
|
38
|
+
The Engin framework gives you:
|
39
39
|
|
40
40
|
- A fully-featured dependency injection system.
|
41
41
|
- A robust application runtime with lifecycle hooks and supervised background tasks.
|
42
|
-
- Zero boiler-plate code reuse across
|
42
|
+
- Zero boiler-plate code reuse across applications.
|
43
43
|
- Integrations for other frameworks such as FastAPI.
|
44
44
|
- Full async support.
|
45
45
|
- CLI commands to aid local development.
|
@@ -47,7 +47,7 @@ The Engin framework includes:
|
|
47
47
|
|
48
48
|
## Installation
|
49
49
|
|
50
|
-
Engin is available on PyPI, install using your favourite dependency manager:
|
50
|
+
Engin is available on PyPI, install it using your favourite dependency manager:
|
51
51
|
|
52
52
|
- `pip install engin`
|
53
53
|
- `poetry add engin`
|
@@ -55,13 +55,13 @@ Engin is available on PyPI, install using your favourite dependency manager:
|
|
55
55
|
|
56
56
|
## Example
|
57
57
|
|
58
|
-
A small example which shows some of the
|
59
|
-
makes
|
58
|
+
A small example which shows some of the features of Engin. This application
|
59
|
+
makes 3 http requests and shuts itself down.
|
60
60
|
|
61
61
|
```python
|
62
62
|
import asyncio
|
63
63
|
from httpx import AsyncClient
|
64
|
-
from engin import Engin, Invoke, Lifecycle, Provide, Supervisor
|
64
|
+
from engin import Engin, Invoke, Lifecycle, OnException, Provide, Supervisor
|
65
65
|
|
66
66
|
|
67
67
|
def httpx_client_factory(lifecycle: Lifecycle) -> AsyncClient:
|
@@ -76,13 +76,17 @@ async def main(
|
|
76
76
|
httpx_client: AsyncClient,
|
77
77
|
supervisor: Supervisor,
|
78
78
|
) -> None:
|
79
|
-
async def
|
80
|
-
|
81
|
-
|
82
|
-
|
79
|
+
async def http_requests_task():
|
80
|
+
# simulate a background task
|
81
|
+
for x in range(3):
|
82
|
+
await httpx_client.get("https://httpbin.org/get")
|
83
|
+
await asyncio.sleep(1.0)
|
84
|
+
# raise an error to shutdown the application, normally you wouldn't do this!
|
85
|
+
raise RuntimeError("Forcing shutdown")
|
86
|
+
|
87
|
+
# supervise the http requests as part of the application's lifecycle
|
88
|
+
supervisor.supervise(http_requests_task, on_exception=OnException.SHUTDOWN)
|
83
89
|
|
84
|
-
# supervise the http request as part of the application's lifecycle
|
85
|
-
supervisor.supervise(http_request)
|
86
90
|
|
87
91
|
# define our modular application
|
88
92
|
engin = Engin(Provide(httpx_client_factory), Invoke(main))
|
@@ -97,6 +101,15 @@ With logs enabled this will output:
|
|
97
101
|
INFO:engin:starting engin
|
98
102
|
INFO:engin:startup complete
|
99
103
|
INFO:httpx:HTTP Request: GET https://httpbin.org/get "HTTP/1.1 200 OK"
|
104
|
+
INFO:httpx:HTTP Request: GET https://httpbin.org/get "HTTP/1.1 200 OK"
|
105
|
+
INFO:httpx:HTTP Request: GET https://httpbin.org/get "HTTP/1.1 200 OK"
|
106
|
+
ERROR:engin:supervisor task 'http_requests_task' raised RuntimeError, starting shutdown
|
107
|
+
Traceback (most recent call last):
|
108
|
+
File "C:\dev\python\engin\src\engin\_supervisor.py", line 58, in __call__
|
109
|
+
await self.factory()
|
110
|
+
File "C:\dev\python\engin\readme_example.py", line 29, in http_requests_task
|
111
|
+
raise RuntimeError("Forcing shutdown")
|
112
|
+
RuntimeError: Forcing shutdown
|
100
113
|
INFO:engin:stopping engin
|
101
114
|
INFO:engin:shutdown complete
|
102
115
|
```
|
@@ -106,4 +119,4 @@ INFO:engin:shutdown complete
|
|
106
119
|
Engin is heavily inspired by [Uber's Fx framework for Go](https://github.com/uber-go/fx)
|
107
120
|
and the [Injector framework for Python](https://github.com/python-injector/injector).
|
108
121
|
|
109
|
-
They are both great projects, check them out.
|
122
|
+
They are both great projects, go check them out.
|
@@ -1,27 +1,27 @@
|
|
1
1
|
engin/__init__.py,sha256=O0vS570kZFBq7Kwy4FgeJFIhfo4aIg5mv_Z_9vAQRio,577
|
2
|
-
engin/_assembler.py,sha256=
|
2
|
+
engin/_assembler.py,sha256=0uXgtcO5M3EHg0I-TQK9y7LOzfxkLFmKia-zLyVHaxA,11178
|
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=oGaf_iedMNKxl3rbADpPzIvNtTx1Pfs-6o0e8yRrmHk,9532
|
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
|
9
9
|
engin/_option.py,sha256=nZcdrehp1QwgxMUoIpsM0PJuu1q1pbXzhcVsetbsHpc,223
|
10
|
-
engin/_supervisor.py,sha256=
|
10
|
+
engin/_supervisor.py,sha256=HI0D4StqSJZE2l6x7RtouRLKWx1HOhUmLHqu8pUcWbQ,4343
|
11
11
|
engin/_type_utils.py,sha256=H3Tl-kJr2wY2RhaTXP9GrMqa2RsXMijHbjHKe1AxGmc,2276
|
12
|
-
engin/exceptions.py,sha256
|
12
|
+
engin/exceptions.py,sha256=lSMOJI4Yl-VIM0yDzFWbPhC0mQm4f0WvGULr9SldIaY,2353
|
13
13
|
engin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
14
|
engin/_cli/__init__.py,sha256=Ixk3NoZeIN8Bj53I625uqJdLyyT9Gpbe_4GtNy-KQwM,636
|
15
|
-
engin/_cli/_check.py,sha256=
|
15
|
+
engin/_cli/_check.py,sha256=YA37Gi4rimKIH-XMs7SEAFkSRNBIMG8OCKfF3W1V3-g,1976
|
16
16
|
engin/_cli/_common.py,sha256=6tyjxAkROCViw0LOFdx-X1U-iSXKyeW5CoE9UxWRybI,3282
|
17
|
-
engin/_cli/_graph.html,sha256=
|
18
|
-
engin/_cli/_graph.py,sha256=
|
19
|
-
engin/_cli/_inspect.py,sha256=
|
17
|
+
engin/_cli/_graph.html,sha256=YIv34LR00aWsWgjNrqO4XBNu4frPo_y-i1CijaZyySo,29073
|
18
|
+
engin/_cli/_graph.py,sha256=MsxsNpL1v0v1AUT57ZS97l1diwacqRaPdVBObHHIGJE,6753
|
19
|
+
engin/_cli/_inspect.py,sha256=_uzldpHA51IX4srpUGzL4lZNiepqucsO9M3Zo83XBBM,3159
|
20
20
|
engin/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
21
21
|
engin/extensions/asgi.py,sha256=7vQFaVs1jxq1KbhHGN8k7x2UFab6SPUq2_hXfX6HiXU,3329
|
22
22
|
engin/extensions/fastapi.py,sha256=7N6i-eZUEZRPo7kcvjS7kbRSY5QAPyKJXSeongSQ-OA,6371
|
23
|
-
engin-0.1.
|
24
|
-
engin-0.1.
|
25
|
-
engin-0.1.
|
26
|
-
engin-0.1.
|
27
|
-
engin-0.1.
|
23
|
+
engin-0.1.0rc2.dist-info/METADATA,sha256=I7BtKglKAs30NQ6n73p3gzLhZhxcvsIZXuuM356Ipa4,3951
|
24
|
+
engin-0.1.0rc2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
25
|
+
engin-0.1.0rc2.dist-info/entry_points.txt,sha256=sW247zZUMxm0b5UKYvPuqQQljYDtU-j2zK3cu7gHwM0,41
|
26
|
+
engin-0.1.0rc2.dist-info/licenses/LICENSE,sha256=XHh5LPUPKZWTBqBv2xxN2RU7D59nHoiJGb5RIt8f45w,1070
|
27
|
+
engin-0.1.0rc2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|