engin 0.0.16__tar.gz → 0.0.18__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.0.16 → engin-0.0.18}/CHANGELOG.md +20 -0
- {engin-0.0.16 → engin-0.0.18}/PKG-INFO +1 -1
- {engin-0.0.16 → engin-0.0.18}/pyproject.toml +1 -1
- {engin-0.0.16 → engin-0.0.18}/src/engin/_assembler.py +7 -2
- {engin-0.0.16 → engin-0.0.18}/src/engin/_cli/__init__.py +11 -0
- engin-0.0.18/src/engin/_cli/_common.py +51 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/_cli/_graph.py +5 -36
- engin-0.0.18/src/engin/_cli/_inspect.py +94 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/_dependency.py +28 -18
- {engin-0.0.16 → engin-0.0.18}/src/engin/_graph.py +1 -1
- {engin-0.0.16 → engin-0.0.18}/src/engin/ext/fastapi.py +2 -2
- {engin-0.0.16 → engin-0.0.18}/tests/cli/test_graph.py +1 -1
- engin-0.0.18/tests/cli/test_inspect.py +13 -0
- {engin-0.0.16 → engin-0.0.18}/tests/test_dependencies.py +12 -0
- {engin-0.0.16 → engin-0.0.18}/uv.lock +50 -49
- engin-0.0.16/src/engin/_cli/_utils.py +0 -18
- {engin-0.0.16 → engin-0.0.18}/.github/workflows/check.yaml +0 -0
- {engin-0.0.16 → engin-0.0.18}/.github/workflows/publish.yaml +0 -0
- {engin-0.0.16 → engin-0.0.18}/.gitignore +0 -0
- {engin-0.0.16 → engin-0.0.18}/.readthedocs.yaml +0 -0
- {engin-0.0.16 → engin-0.0.18}/LICENSE +0 -0
- {engin-0.0.16 → engin-0.0.18}/README.md +0 -0
- {engin-0.0.16 → engin-0.0.18}/docs/concepts/engin.md +0 -0
- {engin-0.0.16 → engin-0.0.18}/docs/concepts/invocations.md +0 -0
- {engin-0.0.16 → engin-0.0.18}/docs/concepts/lifecycle.md +0 -0
- {engin-0.0.16 → engin-0.0.18}/docs/concepts/providers.md +0 -0
- {engin-0.0.16 → engin-0.0.18}/docs/getting-started.md +0 -0
- {engin-0.0.16 → engin-0.0.18}/docs/guides/fastapi-graph.png +0 -0
- {engin-0.0.16 → engin-0.0.18}/docs/guides/fastapi.md +0 -0
- {engin-0.0.16 → engin-0.0.18}/docs/index.md +0 -0
- {engin-0.0.16 → engin-0.0.18}/docs/js/readthedocs.js +0 -0
- {engin-0.0.16 → engin-0.0.18}/docs/overrides/main.html +0 -0
- {engin-0.0.16 → engin-0.0.18}/docs/reference.md +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/app.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/common/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/common/db/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/common/db/adapaters/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/common/db/adapaters/memory.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/common/db/block.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/common/db/ports.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/common/starlette/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/common/starlette/endpoint.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/features/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/features/cats/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/features/cats/api/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/features/cats/api/get.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/features/cats/api/post.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/features/cats/block.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/features/cats/domain.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/asgi/main.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/fastapi/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/fastapi/app.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/fastapi/main.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/fastapi/routes/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/fastapi/routes/cats/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/fastapi/routes/cats/adapters/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/fastapi/routes/cats/adapters/repository.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/fastapi/routes/cats/api.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/fastapi/routes/cats/block.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/fastapi/routes/cats/domain.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/fastapi/routes/cats/ports.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/simple/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/examples/simple/main.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/mkdocs.yaml +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/_block.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/_cli/_graph.html +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/_engin.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/_exceptions.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/_introspect.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/_lifecycle.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/_option.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/_type_utils.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/ext/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/ext/asgi.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/src/engin/py.typed +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/acceptance/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/acceptance/test_error_in_shutdown.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/acceptance/test_error_in_start_up.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/acceptance/test_fastapi.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/cli/__init__.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/conftest.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/deps.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/test_assembler.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/test_block.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/test_engin.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/test_graph.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/test_lifecycle.py +0 -0
- {engin-0.0.16 → engin-0.0.18}/tests/test_utils.py +0 -0
@@ -6,6 +6,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
8
|
|
9
|
+
## [0.0.18] - 2025-04-25
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- A new cli option `engin inspect` that can be used to inspect providers, e.g.
|
14
|
+
`engin inspect examples.simple.main:engin --module httpx`
|
15
|
+
|
16
|
+
|
17
|
+
## [0.0.17] - 2025-04-20
|
18
|
+
|
19
|
+
### Added
|
20
|
+
|
21
|
+
- `Provide` now has the `as_type` parameter that `Supply` had previously.
|
22
|
+
|
23
|
+
### Changed
|
24
|
+
|
25
|
+
- Renamed `parameter_types` property on dependencies to `parameter_type_ids` to be more
|
26
|
+
explicit.
|
27
|
+
|
28
|
+
|
9
29
|
## [0.0.16] - 2025-04-16
|
10
30
|
|
11
31
|
### Added
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import asyncio
|
2
2
|
import logging
|
3
3
|
from collections import defaultdict
|
4
|
-
from collections.abc import Iterable
|
4
|
+
from collections.abc import Iterable, Sequence
|
5
5
|
from contextvars import ContextVar
|
6
6
|
from dataclasses import dataclass
|
7
7
|
from inspect import BoundArguments, Signature
|
@@ -75,6 +75,11 @@ class Assembler:
|
|
75
75
|
else:
|
76
76
|
self._multiproviders[type_id].append(provider)
|
77
77
|
|
78
|
+
@property
|
79
|
+
def providers(self) -> Sequence[Provide[Any]]:
|
80
|
+
multi_providers = [p for multi in self._multiproviders.values() for p in multi]
|
81
|
+
return [*self._providers.values(), *multi_providers]
|
82
|
+
|
78
83
|
async def assemble(self, dependency: Dependency[Any, T]) -> AssembledDependency[T]:
|
79
84
|
"""
|
80
85
|
Assemble a dependency.
|
@@ -228,7 +233,7 @@ class Assembler:
|
|
228
233
|
yield from (
|
229
234
|
child_provider
|
230
235
|
for root_provider in root_providers
|
231
|
-
for root_provider_param in root_provider.
|
236
|
+
for root_provider_param in root_provider.parameter_type_ids
|
232
237
|
for child_provider in self._resolve_providers(root_provider_param)
|
233
238
|
)
|
234
239
|
yield from root_providers
|
@@ -1,3 +1,6 @@
|
|
1
|
+
import logging
|
2
|
+
import sys
|
3
|
+
|
1
4
|
try:
|
2
5
|
import typer
|
3
6
|
except ImportError:
|
@@ -7,7 +10,15 @@ except ImportError:
|
|
7
10
|
) from None
|
8
11
|
|
9
12
|
from engin._cli._graph import cli as graph_cli
|
13
|
+
from engin._cli._inspect import cli as inspect_cli
|
14
|
+
|
15
|
+
# mute logging from importing of files + engin's debug logging.
|
16
|
+
logging.disable()
|
17
|
+
|
18
|
+
# add cwd to path to enable local package imports
|
19
|
+
sys.path.insert(0, "")
|
10
20
|
|
11
21
|
app = typer.Typer()
|
12
22
|
|
13
23
|
app.add_typer(graph_cli)
|
24
|
+
app.add_typer(inspect_cli)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
import importlib
|
2
|
+
from typing import Never
|
3
|
+
|
4
|
+
import typer
|
5
|
+
from rich import print
|
6
|
+
from rich.panel import Panel
|
7
|
+
|
8
|
+
from engin import Engin
|
9
|
+
|
10
|
+
|
11
|
+
def print_error(msg: str) -> Never:
|
12
|
+
print(
|
13
|
+
Panel(
|
14
|
+
title="Error",
|
15
|
+
renderable=msg,
|
16
|
+
title_align="left",
|
17
|
+
border_style="red",
|
18
|
+
highlight=True,
|
19
|
+
)
|
20
|
+
)
|
21
|
+
raise typer.Exit(code=1)
|
22
|
+
|
23
|
+
|
24
|
+
COMMON_HELP = {
|
25
|
+
"app": (
|
26
|
+
"The import path of your Engin instance, in the form 'package:application'"
|
27
|
+
", e.g. 'app.main:engin'"
|
28
|
+
)
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
def get_engin_instance(app: str) -> tuple[str, str, Engin]:
|
33
|
+
try:
|
34
|
+
module_name, engin_name = app.split(":", maxsplit=1)
|
35
|
+
except ValueError:
|
36
|
+
print_error("Expected an argument of the form 'module:attribute', e.g. 'myapp:engin'")
|
37
|
+
|
38
|
+
try:
|
39
|
+
module = importlib.import_module(module_name)
|
40
|
+
except ModuleNotFoundError:
|
41
|
+
print_error(f"Unable to find module '{module_name}'")
|
42
|
+
|
43
|
+
try:
|
44
|
+
instance = getattr(module, engin_name)
|
45
|
+
except AttributeError:
|
46
|
+
print_error(f"Module '{module_name}' has no attribute '{engin_name}'")
|
47
|
+
|
48
|
+
if not isinstance(instance, Engin):
|
49
|
+
print_error(f"'{app}' is not an Engin instance")
|
50
|
+
|
51
|
+
return module_name, engin_name, instance
|
@@ -1,8 +1,5 @@
|
|
1
1
|
import contextlib
|
2
|
-
import importlib
|
3
|
-
import logging
|
4
2
|
import socketserver
|
5
|
-
import sys
|
6
3
|
import threading
|
7
4
|
from http.server import BaseHTTPRequestHandler
|
8
5
|
from pathlib import Path
|
@@ -12,8 +9,8 @@ from typing import Annotated, Any
|
|
12
9
|
import typer
|
13
10
|
from rich import print
|
14
11
|
|
15
|
-
from engin import
|
16
|
-
from engin._cli.
|
12
|
+
from engin import Entrypoint, Invoke, TypeId
|
13
|
+
from engin._cli._common import COMMON_HELP, get_engin_instance
|
17
14
|
from engin._dependency import Dependency, Provide, Supply
|
18
15
|
from engin.ext.asgi import ASGIEngin
|
19
16
|
|
@@ -24,53 +21,25 @@ except ImportError:
|
|
24
21
|
|
25
22
|
cli = typer.Typer()
|
26
23
|
|
27
|
-
# mute logging from importing of files + engin's debug logging.
|
28
|
-
logging.disable()
|
29
24
|
|
30
25
|
_APP_ORIGIN = ""
|
31
26
|
|
32
|
-
_CLI_HELP = {
|
33
|
-
"app": (
|
34
|
-
"The import path of your Engin instance, in the form 'package:application'"
|
35
|
-
", e.g. 'app.main:engin'"
|
36
|
-
)
|
37
|
-
}
|
38
|
-
|
39
27
|
|
40
28
|
@cli.command(name="graph")
|
41
29
|
def serve_graph(
|
42
30
|
app: Annotated[
|
43
31
|
str,
|
44
|
-
typer.Argument(help=
|
32
|
+
typer.Argument(help=COMMON_HELP["app"]),
|
45
33
|
],
|
46
34
|
) -> None:
|
47
35
|
"""
|
48
36
|
Creates a visualisation of your application's dependencies.
|
49
37
|
"""
|
50
|
-
|
51
|
-
sys.path.insert(0, "")
|
52
|
-
|
53
|
-
try:
|
54
|
-
module_name, engin_name = app.split(":", maxsplit=1)
|
55
|
-
except ValueError:
|
56
|
-
print_error("Expected an argument of the form 'module:attribute', e.g. 'myapp:engin'")
|
38
|
+
module_name, _, instance = get_engin_instance(app)
|
57
39
|
|
58
40
|
global _APP_ORIGIN
|
59
41
|
_APP_ORIGIN = module_name.split(".", maxsplit=1)[0]
|
60
42
|
|
61
|
-
try:
|
62
|
-
module = importlib.import_module(module_name)
|
63
|
-
except ModuleNotFoundError:
|
64
|
-
print_error(f"unable to find module '{module_name}'")
|
65
|
-
|
66
|
-
try:
|
67
|
-
instance = getattr(module, engin_name)
|
68
|
-
except AttributeError:
|
69
|
-
print_error(f"module '{module_name}' has no attribute '{engin_name}'")
|
70
|
-
|
71
|
-
if not isinstance(instance, Engin):
|
72
|
-
print_error(f"'{app}' is not an Engin instance")
|
73
|
-
|
74
43
|
nodes = instance.graph()
|
75
44
|
|
76
45
|
# transform dependencies into mermaid syntax
|
@@ -165,7 +134,7 @@ def _render_node(node: Dependency, render_block: bool = True) -> str:
|
|
165
134
|
md += f"{_short_name(node.return_type_id)}"
|
166
135
|
return f'{node_id}["`{md}`"]{style}'
|
167
136
|
if isinstance(node, Entrypoint):
|
168
|
-
entrypoint_type = node.
|
137
|
+
entrypoint_type = node.parameter_type_ids[0]
|
169
138
|
md += f"{entrypoint_type}"
|
170
139
|
return f'{node_id}[/"`{md}`"\\]{style}'
|
171
140
|
if isinstance(node, Invoke):
|
@@ -0,0 +1,94 @@
|
|
1
|
+
from typing import Annotated
|
2
|
+
|
3
|
+
import typer
|
4
|
+
from rich import box
|
5
|
+
from rich.console import Console
|
6
|
+
from rich.table import Table
|
7
|
+
|
8
|
+
from engin import Supply
|
9
|
+
from engin._cli._common import COMMON_HELP, get_engin_instance, print_error
|
10
|
+
|
11
|
+
cli = typer.Typer()
|
12
|
+
_CLI_HELP = {
|
13
|
+
"type": "Filter providers by the provided type, e.g. `AsyncClient` or `float[]`",
|
14
|
+
"module": "Filter providers by the provided types' module, e.g. `engin` or `httpx`",
|
15
|
+
"verbose": "Enables verbose output",
|
16
|
+
}
|
17
|
+
|
18
|
+
|
19
|
+
@cli.command(name="inspect")
|
20
|
+
def serve_graph(
|
21
|
+
app: Annotated[
|
22
|
+
str,
|
23
|
+
typer.Argument(help=COMMON_HELP["app"]),
|
24
|
+
],
|
25
|
+
type_: Annotated[
|
26
|
+
str | None,
|
27
|
+
typer.Option("--type", help=_CLI_HELP["type"]),
|
28
|
+
] = None,
|
29
|
+
module: Annotated[
|
30
|
+
str | None,
|
31
|
+
typer.Option(help=_CLI_HELP["module"]),
|
32
|
+
] = None,
|
33
|
+
verbose: Annotated[
|
34
|
+
bool, typer.Option("--verbose", "-v", help=_CLI_HELP["verbose"])
|
35
|
+
] = False,
|
36
|
+
) -> None:
|
37
|
+
"""
|
38
|
+
Shows metadata for all matching providers.
|
39
|
+
|
40
|
+
Examples:
|
41
|
+
|
42
|
+
1. `engin inspect examples.simple.main:engin --module httpx`
|
43
|
+
|
44
|
+
2. `engin inspect examples.simple.main:engin --type AsyncClient`
|
45
|
+
"""
|
46
|
+
module_name, _, instance = get_engin_instance(app)
|
47
|
+
|
48
|
+
console = Console()
|
49
|
+
|
50
|
+
providers = []
|
51
|
+
for provider in instance.assembler.providers:
|
52
|
+
type_id = provider.return_type_id
|
53
|
+
if type_ is not None:
|
54
|
+
type_name = str(type_id).rsplit(".", maxsplit=1)[-1]
|
55
|
+
if type_ != type_name:
|
56
|
+
if verbose:
|
57
|
+
console.print(
|
58
|
+
f"Ignoring '{provider.return_type_id}' as `{type_} != {type_name}",
|
59
|
+
style="dim",
|
60
|
+
)
|
61
|
+
continue
|
62
|
+
if module is not None:
|
63
|
+
module_name = str(type_id).split(".", maxsplit=1)[0]
|
64
|
+
if module != module_name:
|
65
|
+
if verbose:
|
66
|
+
console.print(
|
67
|
+
f"Ignoring '{provider.return_type_id}' as `{module} != {module_name}",
|
68
|
+
style="dim",
|
69
|
+
)
|
70
|
+
continue
|
71
|
+
providers.append(provider)
|
72
|
+
|
73
|
+
matching_provider_count = len(providers)
|
74
|
+
if matching_provider_count == 0:
|
75
|
+
available = sorted(map(str, instance.assembler.providers))
|
76
|
+
print_error(f"No matching providers, available: {available}")
|
77
|
+
|
78
|
+
if matching_provider_count > 1:
|
79
|
+
console.print(f"Found {matching_provider_count} matching providers", style="dim")
|
80
|
+
|
81
|
+
table = Table(show_header=False, show_lines=False, box=box.ASCII)
|
82
|
+
|
83
|
+
for provider in sorted(providers, key=lambda p: p.source_module):
|
84
|
+
is_supply = isinstance(provider, Supply)
|
85
|
+
|
86
|
+
table.add_row("name", str(provider), style="bold", end_section=True)
|
87
|
+
table.add_row("scope", provider.scope or "N/A")
|
88
|
+
table.add_row("func", provider.func_name if not is_supply else "N/A")
|
89
|
+
table.add_row("block", provider.block_name or "N/A")
|
90
|
+
table.add_row("source module", provider.source_module or "N/A")
|
91
|
+
table.add_row("source package", provider.source_package or "N/A")
|
92
|
+
table.add_section()
|
93
|
+
|
94
|
+
console.print(table)
|
@@ -76,7 +76,7 @@ class Dependency(ABC, Option, Generic[P, T]):
|
|
76
76
|
return f"{self._func.__module__}.{self._func.__name__}"
|
77
77
|
|
78
78
|
@property
|
79
|
-
def
|
79
|
+
def parameter_type_ids(self) -> list[TypeId]:
|
80
80
|
parameters = list(self._signature.parameters.values())
|
81
81
|
if not parameters:
|
82
82
|
return []
|
@@ -136,7 +136,7 @@ class Entrypoint(Invoke):
|
|
136
136
|
super().__init__(invocation=_noop)
|
137
137
|
|
138
138
|
@property
|
139
|
-
def
|
139
|
+
def parameter_type_ids(self) -> list[TypeId]:
|
140
140
|
return [TypeId.from_type(self._type)]
|
141
141
|
|
142
142
|
@property
|
@@ -153,7 +153,12 @@ class Entrypoint(Invoke):
|
|
153
153
|
|
154
154
|
class Provide(Dependency[Any, T]):
|
155
155
|
def __init__(
|
156
|
-
self,
|
156
|
+
self,
|
157
|
+
builder: Func[P, T],
|
158
|
+
*,
|
159
|
+
scope: str | None = None,
|
160
|
+
as_type: type | None = None,
|
161
|
+
override: bool = False,
|
157
162
|
) -> None:
|
158
163
|
"""
|
159
164
|
Provide a type via a builder or factory function.
|
@@ -161,19 +166,26 @@ class Provide(Dependency[Any, T]):
|
|
161
166
|
Args:
|
162
167
|
builder: the builder function that returns the type.
|
163
168
|
scope: (optional) associate this provider with a specific scope.
|
164
|
-
|
165
|
-
|
169
|
+
as_type: (optional) allows you to explicitly specify the provided type, e.g.
|
170
|
+
to type erase a concrete type, or to provide a mock implementation.
|
171
|
+
override: (optional) allow this provider to override other providers for the
|
172
|
+
same type from the same package.
|
166
173
|
"""
|
167
174
|
super().__init__(func=builder)
|
168
175
|
self._scope = scope
|
169
176
|
self._override = override
|
177
|
+
self._explicit_type = as_type
|
178
|
+
|
179
|
+
if self._explicit_type is not None:
|
180
|
+
self._signature = self._signature.replace(return_annotation=self._explicit_type)
|
181
|
+
|
170
182
|
self._is_multi = typing.get_origin(self.return_type) is list
|
171
183
|
|
172
184
|
# Validate that the provider does to depend on its own output value, as this will
|
173
185
|
# cause a recursion error and is undefined behaviour wise.
|
174
186
|
if any(
|
175
187
|
self.return_type == param.annotation
|
176
|
-
for param in self.
|
188
|
+
for param in self._signature.parameters.values()
|
177
189
|
):
|
178
190
|
raise ValueError("A provider cannot depend on its own return type")
|
179
191
|
|
@@ -187,6 +199,8 @@ class Provide(Dependency[Any, T]):
|
|
187
199
|
|
188
200
|
@property
|
189
201
|
def return_type(self) -> type[T]:
|
202
|
+
if self._explicit_type is not None:
|
203
|
+
return self._explicit_type
|
190
204
|
if isclass(self._func):
|
191
205
|
return_type = self._func # __init__ returns self
|
192
206
|
else:
|
@@ -253,23 +267,19 @@ class Supply(Provide, Generic[T]):
|
|
253
267
|
function.
|
254
268
|
|
255
269
|
Args:
|
256
|
-
value: the value to Supply
|
257
|
-
as_type: allows you to specify the provided type,
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
package.
|
270
|
+
value: the value to Supply.
|
271
|
+
as_type: (optional) allows you to explicitly specify the provided type, e.g.
|
272
|
+
to type erase a concrete type, or to provide a mock implementation.
|
273
|
+
override: (optional) allow this provider to override other providers for the
|
274
|
+
same type from the same package.
|
262
275
|
"""
|
263
276
|
self._value = value
|
264
|
-
self.
|
265
|
-
if self._type_hint is not None:
|
266
|
-
self._get_val.__annotations__["return"] = as_type
|
267
|
-
super().__init__(builder=self._get_val, override=override)
|
277
|
+
super().__init__(builder=self._get_val, as_type=as_type, override=override)
|
268
278
|
|
269
279
|
@property
|
270
280
|
def return_type(self) -> type[T]:
|
271
|
-
if self.
|
272
|
-
return self.
|
281
|
+
if self._explicit_type is not None:
|
282
|
+
return self._explicit_type
|
273
283
|
if isinstance(self._value, list):
|
274
284
|
return list[type(self._value[0])] # type: ignore[misc,return-value]
|
275
285
|
return type(self._value)
|
@@ -75,7 +75,7 @@ class _FastAPIDependencyGrapher(DependencyGrapher):
|
|
75
75
|
) -> list[Node]:
|
76
76
|
nodes: list[Node] = []
|
77
77
|
for root in roots:
|
78
|
-
for parameter in root.
|
78
|
+
for parameter in root.parameter_type_ids:
|
79
79
|
provider = self._providers[parameter]
|
80
80
|
|
81
81
|
# multiprovider
|
@@ -162,7 +162,7 @@ class APIRouteDependency(Dependency):
|
|
162
162
|
return self._route
|
163
163
|
|
164
164
|
@property
|
165
|
-
def
|
165
|
+
def parameter_type_ids(self) -> list[TypeId]:
|
166
166
|
parameters = list(self._signature.parameters.values())
|
167
167
|
if not parameters:
|
168
168
|
return []
|
@@ -0,0 +1,13 @@
|
|
1
|
+
from typer.testing import CliRunner
|
2
|
+
|
3
|
+
from engin import Engin
|
4
|
+
from engin._cli._inspect import cli
|
5
|
+
from tests.deps import ABlock
|
6
|
+
|
7
|
+
engin = Engin(ABlock)
|
8
|
+
runner = CliRunner()
|
9
|
+
|
10
|
+
|
11
|
+
def test_cli_inspect() -> None:
|
12
|
+
result = runner.invoke(app=cli, args=["tests.cli.test_inspect:engin", "--type", "float[]"])
|
13
|
+
assert result.exit_code == 0
|
@@ -129,3 +129,15 @@ def test_provides_implicit_overrides_allowed_when_3rd_party():
|
|
129
129
|
|
130
130
|
provide_a.apply(engin)
|
131
131
|
provide_b.apply(engin)
|
132
|
+
|
133
|
+
|
134
|
+
def test_provide_as_type():
|
135
|
+
provide = Provide(make_int, as_type=float)
|
136
|
+
assert provide.return_type is float
|
137
|
+
assert provide.signature.return_annotation is float
|
138
|
+
|
139
|
+
|
140
|
+
def test_supply_as_type():
|
141
|
+
supply = Supply(3, as_type=float)
|
142
|
+
assert supply.return_type is float
|
143
|
+
assert supply.signature.return_annotation is float
|
@@ -206,7 +206,7 @@ toml = [
|
|
206
206
|
|
207
207
|
[[package]]
|
208
208
|
name = "engin"
|
209
|
-
version = "0.0.
|
209
|
+
version = "0.0.18"
|
210
210
|
source = { editable = "." }
|
211
211
|
|
212
212
|
[package.optional-dependencies]
|
@@ -299,36 +299,36 @@ wheels = [
|
|
299
299
|
|
300
300
|
[[package]]
|
301
301
|
name = "griffe"
|
302
|
-
version = "1.7.
|
302
|
+
version = "1.7.3"
|
303
303
|
source = { registry = "https://pypi.org/simple" }
|
304
304
|
dependencies = [
|
305
305
|
{ name = "colorama" },
|
306
306
|
]
|
307
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
307
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a9/3e/5aa9a61f7c3c47b0b52a1d930302992229d191bf4bc76447b324b731510a/griffe-1.7.3.tar.gz", hash = "sha256:52ee893c6a3a968b639ace8015bec9d36594961e156e23315c8e8e51401fa50b", size = 395137 }
|
308
308
|
wheels = [
|
309
|
-
{ url = "https://files.pythonhosted.org/packages/
|
309
|
+
{ url = "https://files.pythonhosted.org/packages/58/c6/5c20af38c2a57c15d87f7f38bee77d63c1d2a3689f74fefaf35915dd12b2/griffe-1.7.3-py3-none-any.whl", hash = "sha256:c6b3ee30c2f0f17f30bcdef5068d6ab7a2a4f1b8bf1a3e74b56fffd21e1c5f75", size = 129303 },
|
310
310
|
]
|
311
311
|
|
312
312
|
[[package]]
|
313
313
|
name = "h11"
|
314
|
-
version = "0.
|
314
|
+
version = "0.16.0"
|
315
315
|
source = { registry = "https://pypi.org/simple" }
|
316
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
316
|
+
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 }
|
317
317
|
wheels = [
|
318
|
-
{ url = "https://files.pythonhosted.org/packages/
|
318
|
+
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 },
|
319
319
|
]
|
320
320
|
|
321
321
|
[[package]]
|
322
322
|
name = "httpcore"
|
323
|
-
version = "1.0.
|
323
|
+
version = "1.0.9"
|
324
324
|
source = { registry = "https://pypi.org/simple" }
|
325
325
|
dependencies = [
|
326
326
|
{ name = "certifi" },
|
327
327
|
{ name = "h11" },
|
328
328
|
]
|
329
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
329
|
+
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 }
|
330
330
|
wheels = [
|
331
|
-
{ url = "https://files.pythonhosted.org/packages/
|
331
|
+
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 },
|
332
332
|
]
|
333
333
|
|
334
334
|
[[package]]
|
@@ -527,7 +527,7 @@ wheels = [
|
|
527
527
|
|
528
528
|
[[package]]
|
529
529
|
name = "mkdocs-material"
|
530
|
-
version = "9.6.
|
530
|
+
version = "9.6.12"
|
531
531
|
source = { registry = "https://pypi.org/simple" }
|
532
532
|
dependencies = [
|
533
533
|
{ name = "babel" },
|
@@ -542,9 +542,9 @@ dependencies = [
|
|
542
542
|
{ name = "pymdown-extensions" },
|
543
543
|
{ name = "requests" },
|
544
544
|
]
|
545
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
545
|
+
sdist = { url = "https://files.pythonhosted.org/packages/2d/ef/25fc10dbbb8faeeeb10ed7734d84a347cd2ec5d7200733f11c5553c02608/mkdocs_material-9.6.12.tar.gz", hash = "sha256:add6a6337b29f9ea7912cb1efc661de2c369060b040eb5119855d794ea85b473", size = 3951532 }
|
546
546
|
wheels = [
|
547
|
-
{ url = "https://files.pythonhosted.org/packages/
|
547
|
+
{ url = "https://files.pythonhosted.org/packages/09/00/592940f4d150327a4f455171b2c9d4c3be7779a88e18b0a086183fcd8f06/mkdocs_material-9.6.12-py3-none-any.whl", hash = "sha256:92b4fbdc329e4febc267ca6e2c51e8501fa97b2225c5f4deb4d4e43550f8e61e", size = 8703654 },
|
548
548
|
]
|
549
549
|
|
550
550
|
[[package]]
|
@@ -633,20 +633,20 @@ wheels = [
|
|
633
633
|
|
634
634
|
[[package]]
|
635
635
|
name = "mypy-extensions"
|
636
|
-
version = "1.
|
636
|
+
version = "1.1.0"
|
637
637
|
source = { registry = "https://pypi.org/simple" }
|
638
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
638
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343 }
|
639
639
|
wheels = [
|
640
|
-
{ url = "https://files.pythonhosted.org/packages/
|
640
|
+
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963 },
|
641
641
|
]
|
642
642
|
|
643
643
|
[[package]]
|
644
644
|
name = "packaging"
|
645
|
-
version = "
|
645
|
+
version = "25.0"
|
646
646
|
source = { registry = "https://pypi.org/simple" }
|
647
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
647
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 }
|
648
648
|
wheels = [
|
649
|
-
{ url = "https://files.pythonhosted.org/packages/
|
649
|
+
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 },
|
650
650
|
]
|
651
651
|
|
652
652
|
[[package]]
|
@@ -696,16 +696,16 @@ wheels = [
|
|
696
696
|
|
697
697
|
[[package]]
|
698
698
|
name = "poethepoet"
|
699
|
-
version = "0.
|
699
|
+
version = "0.34.0"
|
700
700
|
source = { registry = "https://pypi.org/simple" }
|
701
701
|
dependencies = [
|
702
702
|
{ name = "pastel" },
|
703
703
|
{ name = "pyyaml" },
|
704
704
|
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
705
705
|
]
|
706
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
706
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b3/f2/3853d6a9a0dac08aa680895839eeab8ec0ed63db375e1f782e623c9309b6/poethepoet-0.34.0.tar.gz", hash = "sha256:86203acce555bbfe45cb6ccac61ba8b16a5784264484195874da457ddabf5850", size = 64474 }
|
707
707
|
wheels = [
|
708
|
-
{ url = "https://files.pythonhosted.org/packages/
|
708
|
+
{ url = "https://files.pythonhosted.org/packages/da/d1/61431afe22577083fcb50614bc5e5aa73aa0ab35e3fc2ae49708a59ff70b/poethepoet-0.34.0-py3-none-any.whl", hash = "sha256:c472d6f0fdb341b48d346f4ccd49779840c15b30dfd6bc6347a80d6274b5e34e", size = 85851 },
|
709
709
|
]
|
710
710
|
|
711
711
|
[[package]]
|
@@ -812,15 +812,16 @@ wheels = [
|
|
812
812
|
|
813
813
|
[[package]]
|
814
814
|
name = "pydantic-settings"
|
815
|
-
version = "2.
|
815
|
+
version = "2.9.1"
|
816
816
|
source = { registry = "https://pypi.org/simple" }
|
817
817
|
dependencies = [
|
818
818
|
{ name = "pydantic" },
|
819
819
|
{ name = "python-dotenv" },
|
820
|
+
{ name = "typing-inspection" },
|
820
821
|
]
|
821
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
822
|
+
sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234 }
|
822
823
|
wheels = [
|
823
|
-
{ url = "https://files.pythonhosted.org/packages/
|
824
|
+
{ url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356 },
|
824
825
|
]
|
825
826
|
|
826
827
|
[[package]]
|
@@ -1007,27 +1008,27 @@ wheels = [
|
|
1007
1008
|
|
1008
1009
|
[[package]]
|
1009
1010
|
name = "ruff"
|
1010
|
-
version = "0.11.
|
1011
|
-
source = { registry = "https://pypi.org/simple" }
|
1012
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
1013
|
-
wheels = [
|
1014
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1015
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1016
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1017
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1018
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1019
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1020
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1021
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1022
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1023
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1024
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1025
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1026
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1027
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1028
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1029
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1030
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1011
|
+
version = "0.11.7"
|
1012
|
+
source = { registry = "https://pypi.org/simple" }
|
1013
|
+
sdist = { url = "https://files.pythonhosted.org/packages/5b/89/6f9c9674818ac2e9cc2f2b35b704b7768656e6b7c139064fc7ba8fbc99f1/ruff-0.11.7.tar.gz", hash = "sha256:655089ad3224070736dc32844fde783454f8558e71f501cb207485fe4eee23d4", size = 4054861 }
|
1014
|
+
wheels = [
|
1015
|
+
{ url = "https://files.pythonhosted.org/packages/b4/ec/21927cb906c5614b786d1621dba405e3d44f6e473872e6df5d1a6bca0455/ruff-0.11.7-py3-none-linux_armv6l.whl", hash = "sha256:d29e909d9a8d02f928d72ab7837b5cbc450a5bdf578ab9ebee3263d0a525091c", size = 10245403 },
|
1016
|
+
{ url = "https://files.pythonhosted.org/packages/e2/af/fec85b6c2c725bcb062a354dd7cbc1eed53c33ff3aa665165871c9c16ddf/ruff-0.11.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dd1fb86b168ae349fb01dd497d83537b2c5541fe0626e70c786427dd8363aaee", size = 11007166 },
|
1017
|
+
{ url = "https://files.pythonhosted.org/packages/31/9a/2d0d260a58e81f388800343a45898fd8df73c608b8261c370058b675319a/ruff-0.11.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d3d7d2e140a6fbbc09033bce65bd7ea29d6a0adeb90b8430262fbacd58c38ada", size = 10378076 },
|
1018
|
+
{ url = "https://files.pythonhosted.org/packages/c2/c4/9b09b45051404d2e7dd6d9dbcbabaa5ab0093f9febcae664876a77b9ad53/ruff-0.11.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4809df77de390a1c2077d9b7945d82f44b95d19ceccf0c287c56e4dc9b91ca64", size = 10557138 },
|
1019
|
+
{ url = "https://files.pythonhosted.org/packages/5e/5e/f62a1b6669870a591ed7db771c332fabb30f83c967f376b05e7c91bccd14/ruff-0.11.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3a0c2e169e6b545f8e2dba185eabbd9db4f08880032e75aa0e285a6d3f48201", size = 10095726 },
|
1020
|
+
{ url = "https://files.pythonhosted.org/packages/45/59/a7aa8e716f4cbe07c3500a391e58c52caf665bb242bf8be42c62adef649c/ruff-0.11.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49b888200a320dd96a68e86736cf531d6afba03e4f6cf098401406a257fcf3d6", size = 11672265 },
|
1021
|
+
{ url = "https://files.pythonhosted.org/packages/dd/e3/101a8b707481f37aca5f0fcc3e42932fa38b51add87bfbd8e41ab14adb24/ruff-0.11.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2b19cdb9cf7dae00d5ee2e7c013540cdc3b31c4f281f1dacb5a799d610e90db4", size = 12331418 },
|
1022
|
+
{ url = "https://files.pythonhosted.org/packages/dd/71/037f76cbe712f5cbc7b852e4916cd3cf32301a30351818d32ab71580d1c0/ruff-0.11.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64e0ee994c9e326b43539d133a36a455dbaab477bc84fe7bfbd528abe2f05c1e", size = 11794506 },
|
1023
|
+
{ url = "https://files.pythonhosted.org/packages/ca/de/e450b6bab1fc60ef263ef8fcda077fb4977601184877dce1c59109356084/ruff-0.11.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bad82052311479a5865f52c76ecee5d468a58ba44fb23ee15079f17dd4c8fd63", size = 13939084 },
|
1024
|
+
{ url = "https://files.pythonhosted.org/packages/0e/2c/1e364cc92970075d7d04c69c928430b23e43a433f044474f57e425cbed37/ruff-0.11.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7940665e74e7b65d427b82bffc1e46710ec7f30d58b4b2d5016e3f0321436502", size = 11450441 },
|
1025
|
+
{ url = "https://files.pythonhosted.org/packages/9d/7d/1b048eb460517ff9accd78bca0fa6ae61df2b276010538e586f834f5e402/ruff-0.11.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:169027e31c52c0e36c44ae9a9c7db35e505fee0b39f8d9fca7274a6305295a92", size = 10441060 },
|
1026
|
+
{ url = "https://files.pythonhosted.org/packages/3a/57/8dc6ccfd8380e5ca3d13ff7591e8ba46a3b330323515a4996b991b10bd5d/ruff-0.11.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:305b93f9798aee582e91e34437810439acb28b5fc1fee6b8205c78c806845a94", size = 10058689 },
|
1027
|
+
{ url = "https://files.pythonhosted.org/packages/23/bf/20487561ed72654147817885559ba2aa705272d8b5dee7654d3ef2dbf912/ruff-0.11.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a681db041ef55550c371f9cd52a3cf17a0da4c75d6bd691092dfc38170ebc4b6", size = 11073703 },
|
1028
|
+
{ url = "https://files.pythonhosted.org/packages/9d/27/04f2db95f4ef73dccedd0c21daf9991cc3b7f29901a4362057b132075aa4/ruff-0.11.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:07f1496ad00a4a139f4de220b0c97da6d4c85e0e4aa9b2624167b7d4d44fd6b6", size = 11532822 },
|
1029
|
+
{ url = "https://files.pythonhosted.org/packages/e1/72/43b123e4db52144c8add336581de52185097545981ff6e9e58a21861c250/ruff-0.11.7-py3-none-win32.whl", hash = "sha256:f25dfb853ad217e6e5f1924ae8a5b3f6709051a13e9dad18690de6c8ff299e26", size = 10362436 },
|
1030
|
+
{ url = "https://files.pythonhosted.org/packages/c5/a0/3e58cd76fdee53d5c8ce7a56d84540833f924ccdf2c7d657cb009e604d82/ruff-0.11.7-py3-none-win_amd64.whl", hash = "sha256:0a931d85959ceb77e92aea4bbedfded0a31534ce191252721128f77e5ae1f98a", size = 11566676 },
|
1031
|
+
{ url = "https://files.pythonhosted.org/packages/68/ca/69d7c7752bce162d1516e5592b1cc6b6668e9328c0d270609ddbeeadd7cf/ruff-0.11.7-py3-none-win_arm64.whl", hash = "sha256:778c1e5d6f9e91034142dfd06110534ca13220bfaad5c3735f6cb844654f6177", size = 10677936 },
|
1031
1032
|
]
|
1032
1033
|
|
1033
1034
|
[[package]]
|
@@ -1155,16 +1156,16 @@ wheels = [
|
|
1155
1156
|
|
1156
1157
|
[[package]]
|
1157
1158
|
name = "uvicorn"
|
1158
|
-
version = "0.34.
|
1159
|
+
version = "0.34.2"
|
1159
1160
|
source = { registry = "https://pypi.org/simple" }
|
1160
1161
|
dependencies = [
|
1161
1162
|
{ name = "click" },
|
1162
1163
|
{ name = "h11" },
|
1163
1164
|
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
1164
1165
|
]
|
1165
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
1166
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a6/ae/9bbb19b9e1c450cf9ecaef06463e40234d98d95bf572fab11b4f19ae5ded/uvicorn-0.34.2.tar.gz", hash = "sha256:0e929828f6186353a80b58ea719861d2629d766293b6d19baf086ba31d4f3328", size = 76815 }
|
1166
1167
|
wheels = [
|
1167
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1168
|
+
{ url = "https://files.pythonhosted.org/packages/b1/4b/4cef6ce21a2aaca9d852a6e84ef4f135d99fcd74fa75105e2fc0c8308acd/uvicorn-0.34.2-py3-none-any.whl", hash = "sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403", size = 62483 },
|
1168
1169
|
]
|
1169
1170
|
|
1170
1171
|
[[package]]
|
@@ -1,18 +0,0 @@
|
|
1
|
-
from typing import Never
|
2
|
-
|
3
|
-
import typer
|
4
|
-
from rich import print
|
5
|
-
from rich.panel import Panel
|
6
|
-
|
7
|
-
|
8
|
-
def print_error(msg: str) -> Never:
|
9
|
-
print(
|
10
|
-
Panel(
|
11
|
-
title="Error",
|
12
|
-
renderable=msg.capitalize(),
|
13
|
-
title_align="left",
|
14
|
-
border_style="red",
|
15
|
-
highlight=True,
|
16
|
-
)
|
17
|
-
)
|
18
|
-
raise typer.Exit(code=1)
|
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
|
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
|