ashka-lifecycle 0.2.0__tar.gz → 0.2.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ashka-lifecycle
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: dishka lifecycle support
5
5
  Author: handsome-Druid
6
6
  Author-email: handsome-Druid <102826168@qq.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ashka-lifecycle"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  description = "dishka lifecycle support"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10,<3.15"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ashka-lifecycle"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  description = "dishka lifecycle support"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -1,3 +1,5 @@
1
+ import ashka_lifecycle.async_container
2
+ import ashka_lifecycle.container
1
3
  from ashka_lifecycle.entities.scope import AshkaScope
2
4
  from ashka_lifecycle.provider import (
3
5
  provide, # pyright: ignore[reportUnknownVariableType]
@@ -16,3 +18,5 @@ def activate_lifecycle() -> None:
16
18
  Call this function manually before importing dishka to ensure that the
17
19
  dishka lifecycle is activated in advance.
18
20
  """
21
+ ashka_lifecycle.container.activate()
22
+ ashka_lifecycle.async_container.activate()
@@ -0,0 +1,51 @@
1
+ from asyncio import gather
2
+ from collections.abc import Callable, Coroutine
3
+ from logging import getLogger
4
+
5
+ from ashka_lifecycle.entities.bootstrap import (
6
+ bootstrap_types,
7
+ )
8
+
9
+ from dishka import AsyncContainer, Scope
10
+
11
+
12
+ def activate(): ...
13
+
14
+
15
+ _logger = getLogger(__name__)
16
+
17
+ _aenter: Callable[..., Coroutine[None, object, AsyncContainer]] = (
18
+ AsyncContainer.__aenter__
19
+ )
20
+
21
+
22
+ async def __aenter__(self: AsyncContainer) -> AsyncContainer:
23
+ aenter: AsyncContainer = await _aenter(self)
24
+
25
+ if self.scope is Scope.APP:
26
+ _logger.debug("Initiating bootstrap factories.")
27
+ await gather(
28
+ *(
29
+ self.get(key.type_hint, key.component)
30
+ for key in self.registry.factories
31
+ if key.type_hint in bootstrap_types
32
+ )
33
+ )
34
+ else:
35
+ _logger.debug(
36
+ f"'<dishka_container>.scope': {self.scope!r} is not 'Scope.APP', skipping bootstrap"
37
+ )
38
+
39
+ return aenter
40
+
41
+
42
+ async def init(self: AsyncContainer) -> None:
43
+ if not self.scope is Scope.APP:
44
+ _logger.warning(
45
+ f"'<dishka_container>.scope': {self.scope!r} is not 'Scope.APP', 'container.init()' won't do any bootstrap."
46
+ )
47
+ await self.__aenter__()
48
+
49
+
50
+ AsyncContainer.__aenter__ = __aenter__
51
+ AsyncContainer.init = init # pyright: ignore[reportAttributeAccessIssue]
@@ -0,0 +1,44 @@
1
+ from collections.abc import Callable
2
+ from logging import getLogger
3
+
4
+ from ashka_lifecycle.entities.bootstrap import (
5
+ bootstrap_types,
6
+ )
7
+
8
+ from dishka import Container, Scope
9
+
10
+
11
+ def activate(): ...
12
+
13
+
14
+ _logger = getLogger(__name__)
15
+
16
+ _enter: Callable[..., Container] = Container.__enter__
17
+
18
+
19
+ def __enter__(self: Container) -> Container:
20
+ enter: Container = _enter(self)
21
+
22
+ if self.scope is Scope.APP:
23
+ _logger.debug("Initiating bootstrap factories.")
24
+ for key in self.registry.factories:
25
+ if key.type_hint in bootstrap_types:
26
+ self.get(key.type_hint, key.component)
27
+ else:
28
+ _logger.debug(
29
+ f"'<dishka_container>.scope': {self.scope!r} is not 'Scope.APP', skipping bootstrap"
30
+ )
31
+
32
+ return enter
33
+
34
+
35
+ def init(self: Container) -> None:
36
+ if not self.scope is Scope.APP:
37
+ _logger.warning(
38
+ f"'<dishka_container>.scope': {self.scope!r} is not 'Scope.APP', 'container.init()' won't do any bootstrap."
39
+ )
40
+ self.__enter__()
41
+
42
+
43
+ Container.__enter__ = __enter__
44
+ Container.init = init # pyright: ignore[reportAttributeAccessIssue]
@@ -0,0 +1,110 @@
1
+ from collections.abc import Callable
2
+ from inspect import isbuiltin, isclass, isfunction
3
+ from logging import getLogger
4
+ from typing import Any, NewType, get_origin, get_type_hints, overload
5
+
6
+ from ashka_lifecycle.entities.bootstrap import (
7
+ bootstrap_types,
8
+ )
9
+ from ashka_lifecycle.entities.scope import AshkaScope
10
+
11
+ from dishka import BaseScope, Scope
12
+ from dishka import provide as _provide # pyright: ignore[reportUnknownVariableType]
13
+ from dishka.dependency_source.composite import CompositeDependencySource
14
+ from dishka.entities.provides_marker import ProvideMultiple
15
+ from dishka.provider.exceptions import MissingReturnHintError
16
+ from dishka.provider.make_factory import (
17
+ ProvideSource,
18
+ _clean_result_hint, # pyright: ignore[reportPrivateUsage]
19
+ _guess_factory_type, # pyright: ignore[reportPrivateUsage]
20
+ )
21
+
22
+ __all__: list[str] = ["provide"]
23
+
24
+ _logger = getLogger(__name__)
25
+
26
+
27
+ def activate(): ...
28
+
29
+
30
+ @overload
31
+ def provide(
32
+ *, scope: BaseScope | AshkaScope | None = None, **kwargs: Any
33
+ ) -> Callable[[Callable[..., Any]], CompositeDependencySource]: ...
34
+
35
+
36
+ @overload
37
+ def provide(
38
+ source: ProvideSource, # pyright: ignore[reportUnknownParameterType]
39
+ *,
40
+ scope: BaseScope | AshkaScope | None = None,
41
+ **kwargs: Any,
42
+ ) -> CompositeDependencySource: ...
43
+
44
+
45
+ def provide(
46
+ source: ProvideSource | None = None, # pyright: ignore[reportUnknownParameterType]
47
+ *,
48
+ scope: BaseScope | AshkaScope | None = None,
49
+ **kwargs: Any,
50
+ ) -> (
51
+ CompositeDependencySource
52
+ | Callable[
53
+ [Callable[..., Any]],
54
+ CompositeDependencySource,
55
+ ]
56
+ ):
57
+ if scope is not AshkaScope.BOOTSTRAP:
58
+ return _provide(source, scope=scope, **kwargs)
59
+
60
+ def scoped(source: ProvideSource) -> CompositeDependencySource: # pyright: ignore[reportUnknownParameterType]
61
+ _logger.debug(
62
+ f"Adding {getattr(source, '__name__', source)!r} to bootstrap list..." # pyright: ignore[reportUnknownArgumentType]
63
+ )
64
+ bootstrap_types.add(
65
+ new_type := NewType(
66
+ "ashka_lifecycle.provider.make_factory.provide", AshkaScope
67
+ )
68
+ )
69
+ try:
70
+ return (
71
+ _provide(
72
+ source,
73
+ scope=Scope.APP,
74
+ provides=ProvideMultiple[
75
+ new_type, (_kwargs := kwargs.copy()).pop(provides) # pyright: ignore[reportInvalidTypeArguments]
76
+ ],
77
+ **_kwargs,
78
+ )
79
+ if (provides := "provides") in kwargs
80
+ else _provide(
81
+ source,
82
+ scope=Scope.APP,
83
+ provides=ProvideMultiple[
84
+ new_type,
85
+ source # pyright: ignore[reportInvalidTypeArguments]
86
+ if isclass(source) or isclass(get_origin(source)) # pyright: ignore[reportUnknownArgumentType]
87
+ else _clean_result_hint(
88
+ _guess_factory_type(
89
+ func := getattr(source, "__func__", None) # pyright: ignore[reportUnknownVariableType, reportUnknownArgumentType]
90
+ or (
91
+ source
92
+ if isfunction(source) or isbuiltin(source) # pyright: ignore[reportUnknownArgumentType]
93
+ else getattr(
94
+ source.__call__, # pyright: ignore[reportAttributeAccessIssue, reportUnknownMemberType, reportUnknownArgumentType]
95
+ "__func__",
96
+ source.__call__, # pyright: ignore[reportAttributeAccessIssue, reportUnknownMemberType, reportUnknownArgumentType]
97
+ )
98
+ )
99
+ ),
100
+ get_type_hints(func)["return"], # pyright: ignore[reportUnknownArgumentType]
101
+ ),
102
+ ],
103
+ **kwargs,
104
+ )
105
+ )
106
+ except KeyError as e:
107
+ bootstrap_types.remove(new_type)
108
+ raise MissingReturnHintError(source) from e
109
+
110
+ return scoped if source is None else scoped(source) # pyright: ignore[reportUnknownVariableType]
@@ -1,42 +0,0 @@
1
- from asyncio import gather
2
- from collections.abc import Callable, Coroutine
3
-
4
- from ashka_lifecycle.entities.bootstrap import (
5
- bootstrap_types,
6
- )
7
-
8
- from dishka import AsyncContainer
9
-
10
- _aenter: Callable[..., Coroutine[None, object, AsyncContainer]] = (
11
- AsyncContainer.__aenter__
12
- )
13
-
14
-
15
- async def __aenter__(self: AsyncContainer) -> AsyncContainer:
16
- aenter: AsyncContainer = await _aenter(self)
17
-
18
- await gather(
19
- *(
20
- self.get(key.type_hint, key.component)
21
- for registry in iter(
22
- lambda state=[self.registry]: (
23
- (state[0], state.__setitem__(0, state[0].child_registry))[0] # pyright: ignore[reportCallIssue, reportArgumentType]
24
- if state[0] is not None # pyright: ignore[reportUnnecessaryComparison]
25
- else None
26
- ),
27
- None,
28
- )
29
- for key in registry.factories
30
- if key.type_hint in bootstrap_types
31
- )
32
- )
33
-
34
- return aenter
35
-
36
-
37
- async def init(self: AsyncContainer) -> None:
38
- await self.__aenter__()
39
-
40
-
41
- AsyncContainer.__aenter__ = __aenter__
42
- AsyncContainer.init = init # pyright: ignore[reportAttributeAccessIssue]
@@ -1,37 +0,0 @@
1
- from collections.abc import Callable
2
-
3
- from ashka_lifecycle.entities.bootstrap import (
4
- bootstrap_types,
5
- )
6
-
7
- from dishka import Container
8
-
9
- _enter: Callable[..., Container] = Container.__enter__
10
-
11
-
12
- def __enter__(self: Container) -> Container:
13
- enter: Container = _enter(self)
14
-
15
- [
16
- self.get(key.type_hint, key.component)
17
- for registry in iter(
18
- lambda state=[self.registry]: (
19
- (state[0], state.__setitem__(0, state[0].child_registry))[0] # pyright: ignore[reportCallIssue, reportArgumentType]
20
- if state[0] is not None # pyright: ignore[reportUnnecessaryComparison]
21
- else None
22
- ),
23
- None,
24
- )
25
- for key in registry.factories
26
- if key.type_hint in bootstrap_types
27
- ]
28
-
29
- return enter
30
-
31
-
32
- def init(self: Container) -> None:
33
- self.__enter__()
34
-
35
-
36
- Container.__enter__ = __enter__
37
- Container.init = init # pyright: ignore[reportAttributeAccessIssue]
@@ -1,92 +0,0 @@
1
- from collections.abc import Callable
2
- from inspect import isbuiltin, isclass, isfunction
3
- from typing import Any, NewType, get_origin, get_type_hints, overload
4
-
5
- from ashka_lifecycle.entities.bootstrap import (
6
- bootstrap_types,
7
- )
8
- from ashka_lifecycle.entities.scope import AshkaScope
9
-
10
- from dishka import BaseScope, Scope
11
- from dishka import provide as _provide # pyright: ignore[reportUnknownVariableType]
12
- from dishka.dependency_source.composite import CompositeDependencySource
13
- from dishka.entities.provides_marker import ProvideMultiple
14
- from dishka.provider.make_factory import (
15
- ProvideSource,
16
- _clean_result_hint, # pyright: ignore[reportPrivateUsage]
17
- _guess_factory_type, # pyright: ignore[reportPrivateUsage]
18
- )
19
-
20
- __all__: list[str] = ["provide"]
21
-
22
-
23
- @overload
24
- def provide(
25
- *, scope: BaseScope | AshkaScope | None = None, **kwargs: Any
26
- ) -> Callable[[Callable[..., Any]], CompositeDependencySource]: ...
27
-
28
-
29
- @overload
30
- def provide(
31
- source: ProvideSource, # pyright: ignore[reportUnknownParameterType]
32
- *,
33
- scope: BaseScope | AshkaScope | None = None,
34
- **kwargs: Any,
35
- ) -> CompositeDependencySource: ...
36
-
37
-
38
- def provide(
39
- source: ProvideSource | None = None, # pyright: ignore[reportUnknownParameterType]
40
- *,
41
- scope: BaseScope | AshkaScope | None = None,
42
- **kwargs: Any,
43
- ) -> (
44
- CompositeDependencySource
45
- | Callable[
46
- [Callable[..., Any]],
47
- CompositeDependencySource,
48
- ]
49
- ):
50
- if scope is not AshkaScope.BOOTSTRAP:
51
- return _provide(source, scope=scope, **kwargs)
52
-
53
- def scoped(source: ProvideSource) -> CompositeDependencySource: # pyright: ignore[reportUnknownParameterType]
54
- return (
55
- _provide(
56
- source,
57
- scope=Scope.APP,
58
- provides=ProvideMultiple[
59
- new_type, (_kwargs := kwargs.copy()).pop(provides) # pyright: ignore[reportInvalidTypeArguments]
60
- ],
61
- **_kwargs,
62
- )
63
- if bootstrap_types.add(new_type := NewType("_", object)) is None
64
- and (provides := "provides") in kwargs
65
- else _provide(
66
- source,
67
- scope=Scope.APP,
68
- provides=ProvideMultiple[
69
- new_type,
70
- source # pyright: ignore[reportInvalidTypeArguments]
71
- if isclass(source) or isclass(get_origin(source)) # pyright: ignore[reportUnknownArgumentType]
72
- else _clean_result_hint(
73
- _guess_factory_type(
74
- func := getattr(source, "__func__", None) # pyright: ignore[reportUnknownVariableType, reportUnknownArgumentType]
75
- or (
76
- source
77
- if isfunction(source) or isbuiltin(source) # pyright: ignore[reportUnknownArgumentType]
78
- else getattr(
79
- source.__call__, # pyright: ignore[reportAttributeAccessIssue, reportUnknownMemberType, reportUnknownArgumentType]
80
- "__func__",
81
- source.__call__, # pyright: ignore[reportAttributeAccessIssue, reportUnknownMemberType, reportUnknownArgumentType]
82
- )
83
- )
84
- ),
85
- get_type_hints(func)["return"], # pyright: ignore[reportUnknownArgumentType]
86
- ),
87
- ],
88
- **kwargs,
89
- )
90
- )
91
-
92
- return scoped if source is None else scoped(source) # pyright: ignore[reportUnknownVariableType]