engin 0.0.17__py3-none-any.whl → 0.0.19__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/__init__.py CHANGED
@@ -1,9 +1,7 @@
1
- from engin import ext
2
1
  from engin._assembler import Assembler
3
2
  from engin._block import Block, invoke, provide
4
3
  from engin._dependency import Entrypoint, Invoke, Provide, Supply
5
4
  from engin._engin import Engin
6
- from engin._exceptions import ProviderError
7
5
  from engin._lifecycle import Lifecycle
8
6
  from engin._option import Option
9
7
  from engin._type_utils import TypeId
@@ -17,10 +15,8 @@ __all__ = [
17
15
  "Lifecycle",
18
16
  "Option",
19
17
  "Provide",
20
- "ProviderError",
21
18
  "Supply",
22
19
  "TypeId",
23
- "ext",
24
20
  "invoke",
25
21
  "provide",
26
22
  ]
engin/_assembler.py CHANGED
@@ -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
@@ -9,8 +9,8 @@ from types import TracebackType
9
9
  from typing import Any, Generic, TypeVar, cast
10
10
 
11
11
  from engin._dependency import Dependency, Provide, Supply
12
- from engin._exceptions import NotInScopeError, ProviderError
13
12
  from engin._type_utils import TypeId
13
+ from engin.exceptions import NotInScopeError, ProviderError
14
14
 
15
15
  LOG = logging.getLogger("engin")
16
16
 
@@ -65,6 +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
69
 
69
70
  for provider in providers:
70
71
  type_id = provider.return_type_id
@@ -75,6 +76,11 @@ class Assembler:
75
76
  else:
76
77
  self._multiproviders[type_id].append(provider)
77
78
 
79
+ @property
80
+ def providers(self) -> Sequence[Provide[Any]]:
81
+ multi_providers = [p for multi in self._multiproviders.values() for p in multi]
82
+ return [*self._providers.values(), *multi_providers]
83
+
78
84
  async def assemble(self, dependency: Dependency[Any, T]) -> AssembledDependency[T]:
79
85
  """
80
86
  Assemble a dependency.
@@ -174,8 +180,8 @@ class Assembler:
174
180
  """
175
181
  Add a provider to the Assembler post-initialisation.
176
182
 
177
- If this replaces an existing provider, this will clear any previously assembled
178
- output for the existing Provider.
183
+ If this replaces an existing provider, this will clear all previously assembled
184
+ output. Note: multiproviders cannot be replaced, they are always appended.
179
185
 
180
186
  Args:
181
187
  provider: the Provide instance to add.
@@ -185,14 +191,13 @@ class Assembler:
185
191
  """
186
192
  type_id = provider.return_type_id
187
193
  if provider.is_multiprovider:
188
- if type_id in self._assembled_outputs:
189
- del self._assembled_outputs[type_id]
190
194
  self._multiproviders[type_id].append(provider)
191
195
  else:
192
- if type_id in self._assembled_outputs:
193
- del self._assembled_outputs[type_id]
194
196
  self._providers[type_id] = provider
195
197
 
198
+ self._assembled_outputs.clear()
199
+ self._graph_cache.clear()
200
+
196
201
  def scope(self, scope: str) -> "_ScopeContextManager":
197
202
  return _ScopeContextManager(scope=scope, assembler=self)
198
203
 
@@ -201,13 +206,14 @@ class Assembler:
201
206
  if provider.scope == scope:
202
207
  self._assembled_outputs.pop(type_id, None)
203
208
 
204
- def _resolve_providers(self, type_id: TypeId) -> Iterable[Provide]:
209
+ def _resolve_providers(self, type_id: TypeId, resolved: set[TypeId]) -> set[Provide]:
205
210
  """
206
211
  Resolves the chain of providers required to satisfy the provider of a given type.
207
212
  Ordering of the return value is very important!
208
-
209
- # TODO: performance optimisation, do not recurse for already satisfied providers?
210
213
  """
214
+ if type_id in self._graph_cache:
215
+ return self._graph_cache[type_id]
216
+
211
217
  if type_id.multi:
212
218
  root_providers = self._multiproviders.get(type_id)
213
219
  else:
@@ -225,22 +231,28 @@ class Assembler:
225
231
  raise LookupError(msg)
226
232
 
227
233
  # providers that must be satisfied to satisfy the root level providers
228
- yield from (
234
+ resolved_providers = {
229
235
  child_provider
230
236
  for root_provider in root_providers
231
237
  for root_provider_param in root_provider.parameter_type_ids
232
- for child_provider in self._resolve_providers(root_provider_param)
233
- )
234
- yield from root_providers
238
+ for child_provider in self._resolve_providers(root_provider_param, resolved)
239
+ if root_provider_param not in resolved
240
+ } | set(root_providers)
241
+
242
+ resolved.add(type_id)
243
+ self._graph_cache[type_id] = resolved_providers
244
+
245
+ return resolved_providers
235
246
 
236
247
  async def _satisfy(self, target: TypeId) -> None:
237
- for provider in self._resolve_providers(target):
248
+ for provider in self._resolve_providers(target, set()):
238
249
  if (
239
250
  not provider.is_multiprovider
240
251
  and provider.return_type_id in self._assembled_outputs
241
252
  ):
242
253
  continue
243
254
  type_id = provider.return_type_id
255
+
244
256
  bound_args = await self._bind_arguments(provider.signature)
245
257
  try:
246
258
  value = await provider(*bound_args.args, **bound_args.kwargs)
@@ -248,6 +260,7 @@ class Assembler:
248
260
  raise ProviderError(
249
261
  provider=provider, error_type=type(err), error_message=str(err)
250
262
  ) from err
263
+
251
264
  if provider.is_multiprovider:
252
265
  if type_id in self._assembled_outputs:
253
266
  self._assembled_outputs[type_id].extend(value)
@@ -264,8 +277,7 @@ class Assembler:
264
277
  args.append(object())
265
278
  continue
266
279
  param_key = TypeId.from_type(param.annotation)
267
- has_dependency = param_key in self._assembled_outputs
268
- if not has_dependency:
280
+ if param_key not in self._assembled_outputs:
269
281
  await self._satisfy(param_key)
270
282
  val = self._assembled_outputs[param_key]
271
283
  if param.kind == param.POSITIONAL_ONLY:
engin/_block.py CHANGED
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, ClassVar
5
5
 
6
6
  from engin._dependency import Dependency, Func, Invoke, Provide
7
7
  from engin._option import Option
8
+ from engin.exceptions import InvalidBlockError
8
9
 
9
10
  if TYPE_CHECKING:
10
11
  from engin._engin import Engin
@@ -42,7 +43,7 @@ def invoke(func_: Func | None = None) -> Func | Callable[[Func], Func]:
42
43
  return _inner(func_)
43
44
 
44
45
 
45
- class Block(Option):
46
+ class Block:
46
47
  """
47
48
  A Block is a collection of providers and invocations.
48
49
 
@@ -74,7 +75,7 @@ class Block(Option):
74
75
 
75
76
  @classmethod
76
77
  def apply(cls, engin: "Engin") -> None:
77
- block_name = cls.name or f"{cls.__name__}"
78
+ block_name = cls.name or cls.__name__
78
79
  for option in chain(cls.options, cls._method_options()):
79
80
  if isinstance(option, Dependency):
80
81
  option._block_name = block_name
@@ -82,8 +83,19 @@ class Block(Option):
82
83
 
83
84
  @classmethod
84
85
  def _method_options(cls) -> Iterable[Provide | Invoke]:
85
- for _, method in inspect.getmembers(cls):
86
+ for name, method in inspect.getmembers(cls, inspect.isfunction):
86
87
  if option := getattr(method, "_opt", None):
87
88
  if not isinstance(option, Provide | Invoke):
88
- raise RuntimeError("Block option is not an instance of Provide or Invoke")
89
+ raise InvalidBlockError(
90
+ block=cls,
91
+ reason="Block option is not an instance of Provide or Invoke",
92
+ )
89
93
  yield option
94
+ else:
95
+ raise InvalidBlockError(
96
+ block=cls,
97
+ reason=(
98
+ f"Method '{name}' is not a Provider or Invocation, did you "
99
+ "forget to decorate it?"
100
+ ),
101
+ )
engin/_cli/__init__.py CHANGED
@@ -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)
engin/_cli/_common.py ADDED
@@ -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
engin/_cli/_graph.py CHANGED
@@ -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,65 +9,37 @@ from typing import Annotated, Any
12
9
  import typer
13
10
  from rich import print
14
11
 
15
- from engin import Engin, Entrypoint, Invoke, TypeId
16
- from engin._cli._utils import print_error
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
- from engin.ext.asgi import ASGIEngin
15
+ from engin.extensions.asgi import ASGIEngin
19
16
 
20
17
  try:
21
- from engin.ext.fastapi import APIRouteDependency
18
+ from engin.extensions.fastapi import APIRouteDependency
22
19
  except ImportError:
23
20
  APIRouteDependency = None # type: ignore[assignment,misc]
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=_CLI_HELP["app"]),
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
- # add cwd to path to enable local package imports
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
engin/_cli/_inspect.py ADDED
@@ -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)
engin/_dependency.py CHANGED
@@ -175,47 +175,37 @@ class Provide(Dependency[Any, T]):
175
175
  self._scope = scope
176
176
  self._override = override
177
177
  self._explicit_type = as_type
178
+ self._return_type = self._resolve_return_type()
179
+ self._return_type_id = TypeId.from_type(self._return_type)
178
180
 
179
181
  if self._explicit_type is not None:
180
182
  self._signature = self._signature.replace(return_annotation=self._explicit_type)
181
183
 
182
- self._is_multi = typing.get_origin(self.return_type) is list
184
+ self._is_multi = typing.get_origin(self._return_type) is list
183
185
 
184
186
  # Validate that the provider does to depend on its own output value, as this will
185
187
  # cause a recursion error and is undefined behaviour wise.
186
188
  if any(
187
- self.return_type == param.annotation
189
+ self._return_type == param.annotation
188
190
  for param in self._signature.parameters.values()
189
191
  ):
190
192
  raise ValueError("A provider cannot depend on its own return type")
191
193
 
192
194
  # Validate that multiproviders only return a list of one type.
193
195
  if self._is_multi:
194
- args = typing.get_args(self.return_type)
196
+ args = typing.get_args(self._return_type)
195
197
  if len(args) != 1:
196
198
  raise ValueError(
197
- f"A multiprovider must be of the form list[X], not '{self.return_type}'"
199
+ f"A multiprovider must be of the form list[X], not '{self._return_type}'"
198
200
  )
199
201
 
200
202
  @property
201
203
  def return_type(self) -> type[T]:
202
- if self._explicit_type is not None:
203
- return self._explicit_type
204
- if isclass(self._func):
205
- return_type = self._func # __init__ returns self
206
- else:
207
- try:
208
- return_type = get_type_hints(self._func, include_extras=True)["return"]
209
- except KeyError as err:
210
- raise RuntimeError(
211
- f"Dependency '{self.name}' requires a return typehint"
212
- ) from err
213
-
214
- return return_type
204
+ return self._return_type
215
205
 
216
206
  @property
217
207
  def return_type_id(self) -> TypeId:
218
- return TypeId.from_type(self.return_type)
208
+ return self._return_type_id
219
209
 
220
210
  @property
221
211
  def is_multiprovider(self) -> bool:
@@ -255,6 +245,21 @@ class Provide(Dependency[Any, T]):
255
245
  def __str__(self) -> str:
256
246
  return f"Provide({self.return_type_id})"
257
247
 
248
+ def _resolve_return_type(self) -> type[T]:
249
+ if self._explicit_type is not None:
250
+ return self._explicit_type
251
+ if isclass(self._func):
252
+ return_type = self._func # __init__ returns self
253
+ else:
254
+ try:
255
+ return_type = get_type_hints(self._func, include_extras=True)["return"]
256
+ except KeyError as err:
257
+ raise RuntimeError(
258
+ f"Dependency '{self.name}' requires a return typehint"
259
+ ) from err
260
+
261
+ return return_type
262
+
258
263
 
259
264
  class Supply(Provide, Generic[T]):
260
265
  def __init__(
@@ -276,8 +281,7 @@ class Supply(Provide, Generic[T]):
276
281
  self._value = value
277
282
  super().__init__(builder=self._get_val, as_type=as_type, override=override)
278
283
 
279
- @property
280
- def return_type(self) -> type[T]:
284
+ def _resolve_return_type(self) -> type[T]:
281
285
  if self._explicit_type is not None:
282
286
  return self._explicit_type
283
287
  if isinstance(self._value, list):
@@ -1,7 +1,10 @@
1
- from typing import Any
1
+ from typing import TYPE_CHECKING, Any
2
2
 
3
3
  from engin._dependency import Provide
4
4
 
5
+ if TYPE_CHECKING:
6
+ from engin._block import Block
7
+
5
8
 
6
9
  class EnginError(Exception):
7
10
  """
@@ -15,6 +18,20 @@ class AssemblerError(EnginError):
15
18
  """
16
19
 
17
20
 
21
+ class InvalidBlockError(EnginError):
22
+ """
23
+ Raised when an invalid block is instantiated.
24
+ """
25
+
26
+ def __init__(self, block: "type[Block]", reason: str) -> None:
27
+ self.block = block
28
+ self.block_name = block.name or block.__name__
29
+ self.message = f"block '{self.block_name}' is invalid, reason: '{reason}'"
30
+
31
+ def __str__(self) -> str:
32
+ return self.message
33
+
34
+
18
35
  class ProviderError(AssemblerError):
19
36
  """
20
37
  Raised when a Provider errors during Assembly.
@@ -52,3 +69,12 @@ class NotInScopeError(AssemblerError):
52
69
 
53
70
  def __str__(self) -> str:
54
71
  return self.message
72
+
73
+
74
+ __all__ = [
75
+ "AssemblerError",
76
+ "EnginError",
77
+ "InvalidBlockError",
78
+ "NotInScopeError",
79
+ "ProviderError",
80
+ ]
@@ -10,7 +10,7 @@ from engin import Assembler, Engin, Entrypoint, Invoke, Option
10
10
  from engin._dependency import Dependency, Supply, _noop
11
11
  from engin._graph import DependencyGrapher, Node
12
12
  from engin._type_utils import TypeId
13
- from engin.ext.asgi import ASGIEngin
13
+ from engin.extensions.asgi import ASGIEngin
14
14
 
15
15
  try:
16
16
  from fastapi import APIRouter, FastAPI
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engin
3
- Version: 0.0.17
3
+ Version: 0.0.19
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/
@@ -0,0 +1,25 @@
1
+ engin/__init__.py,sha256=A8TE_ci7idoR683535YoBrWZbYTgXXS-q7Y2y51nZ5M,486
2
+ engin/_assembler.py,sha256=-ENSrXPMWacionIYrTSQO7th9DDBOPyAT8ybPbBRtQw,11318
3
+ engin/_block.py,sha256=IacP4PoJKRhSQCbQSdoyCtmu362a4vj6qoUQKyaJwzI,3062
4
+ engin/_dependency.py,sha256=Nfq6L92LN4X53QpiMCIF3MjmWfuntYVOnZmmoPYYJEw,9165
5
+ engin/_engin.py,sha256=yIpZdeqvm8hv0RxOV0veFuvyu9xQ054JSaeuUWwHdOQ,7380
6
+ engin/_graph.py,sha256=y1g7Lm_Zy5GPEgRsggCKV5DDaDzcwUl8v3IZCK8jyGI,1631
7
+ engin/_introspect.py,sha256=VdREX6Lhhga5SnEP9G7mjHkgJR4mpqk_SMnmL2zTcqY,966
8
+ engin/_lifecycle.py,sha256=cSWe3euZkmpxmUPFvph2lsTtvuZbxttEfBL-RnOI7lo,5325
9
+ engin/_option.py,sha256=nZcdrehp1QwgxMUoIpsM0PJuu1q1pbXzhcVsetbsHpc,223
10
+ engin/_type_utils.py,sha256=Pmm4m1_WdevT5KTe8tzY_BseNxPyhu_nKsLGgyNcPpo,2247
11
+ engin/exceptions.py,sha256=-VPwPReZb9YEIkrWMR9TW2K5HEwmHHgEO7QWH6wfV8c,1946
12
+ engin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ engin/_cli/__init__.py,sha256=koD5WTkZXb8QQIiVU5bJiSR1wwPGb5rv2iwd-v-BA7A,564
14
+ engin/_cli/_common.py,sha256=zMYb1Bs1yUuR3qf3r6WuVozYzDwHJvTVthVbTQfTF9w,1261
15
+ engin/_cli/_graph.html,sha256=rR5dnDKoz7KtSff0ERCi2UKuoH_Z03MRYiXI_W03G5k,2430
16
+ engin/_cli/_graph.py,sha256=HMC91nWvTOr6_czPBNx1RU55Ib3qesJRCmbnL2DsdDk,4659
17
+ engin/_cli/_inspect.py,sha256=0jm25d4wcbXVNJkyaeECSKY-irsxd-EIYBH1GDW_Yjc,3163
18
+ engin/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ engin/extensions/asgi.py,sha256=d5Z6gtMVWDZdAlvrTaMt987sKyiq__A0X4gJQ7IETmA,3247
20
+ engin/extensions/fastapi.py,sha256=e8F4L_nZ9dU9j8mb9lXKwJG6CTu5aIk4N5faRj4EyUA,6369
21
+ engin-0.0.19.dist-info/METADATA,sha256=Rb1VPxLjnzVxhnq8Llie5XRxpI0GANR-dK31BEcPAqg,2354
22
+ engin-0.0.19.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
+ engin-0.0.19.dist-info/entry_points.txt,sha256=sW247zZUMxm0b5UKYvPuqQQljYDtU-j2zK3cu7gHwM0,41
24
+ engin-0.0.19.dist-info/licenses/LICENSE,sha256=XHh5LPUPKZWTBqBv2xxN2RU7D59nHoiJGb5RIt8f45w,1070
25
+ engin-0.0.19.dist-info/RECORD,,
engin/_cli/_utils.py DELETED
@@ -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)
@@ -1,24 +0,0 @@
1
- engin/__init__.py,sha256=rBTteMLAVKg4TJSaMElJUwz72BA_X7nBTREg-I-bWhA,584
2
- engin/_assembler.py,sha256=r2Vr9UO7pHYvj71087PIJYT9lFBNPni3x34MtjMHN7A,10952
3
- engin/_block.py,sha256=8ysWrmHkWpTm6bmSc6jZVoO0Ax5Svu1HwxpZwAtIF_o,2617
4
- engin/_dependency.py,sha256=5x4_0QvHtqv6R_brKHRc-INKE4oMh1JU8-9RCmulp4Q,8976
5
- engin/_engin.py,sha256=yIpZdeqvm8hv0RxOV0veFuvyu9xQ054JSaeuUWwHdOQ,7380
6
- engin/_exceptions.py,sha256=UzMppJWDk_Hx3qWAypcPVLw9OYCibqiZjLYeTl22zaE,1355
7
- engin/_graph.py,sha256=y1g7Lm_Zy5GPEgRsggCKV5DDaDzcwUl8v3IZCK8jyGI,1631
8
- engin/_introspect.py,sha256=VdREX6Lhhga5SnEP9G7mjHkgJR4mpqk_SMnmL2zTcqY,966
9
- engin/_lifecycle.py,sha256=cSWe3euZkmpxmUPFvph2lsTtvuZbxttEfBL-RnOI7lo,5325
10
- engin/_option.py,sha256=nZcdrehp1QwgxMUoIpsM0PJuu1q1pbXzhcVsetbsHpc,223
11
- engin/_type_utils.py,sha256=Pmm4m1_WdevT5KTe8tzY_BseNxPyhu_nKsLGgyNcPpo,2247
12
- engin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- engin/_cli/__init__.py,sha256=lp1KiBpcgk_dZU5V9DjgLPwmp0ja444fwLH2CYCscNc,302
14
- engin/_cli/_graph.html,sha256=rR5dnDKoz7KtSff0ERCi2UKuoH_Z03MRYiXI_W03G5k,2430
15
- engin/_cli/_graph.py,sha256=YZ0awBLtWD5W6xrHO9ueMnk_EIsYM4_j_bmquiLsb2Y,5542
16
- engin/_cli/_utils.py,sha256=AQFtLO8qjYRCTQc9A8Z1HVf7eZr8iGWogxbYzsgIkS4,360
17
- engin/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- engin/ext/asgi.py,sha256=d5Z6gtMVWDZdAlvrTaMt987sKyiq__A0X4gJQ7IETmA,3247
19
- engin/ext/fastapi.py,sha256=TGNf0LFLaTLMLlAycH7GgP_GcBld262v9xboGOwhvgE,6362
20
- engin-0.0.17.dist-info/METADATA,sha256=1SUQZwsFr3neO0WJ_gLLv90kgJCcBNUbwWWi2zZZ77Q,2354
21
- engin-0.0.17.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
22
- engin-0.0.17.dist-info/entry_points.txt,sha256=sW247zZUMxm0b5UKYvPuqQQljYDtU-j2zK3cu7gHwM0,41
23
- engin-0.0.17.dist-info/licenses/LICENSE,sha256=XHh5LPUPKZWTBqBv2xxN2RU7D59nHoiJGb5RIt8f45w,1070
24
- engin-0.0.17.dist-info/RECORD,,
File without changes
File without changes
File without changes