ashka-lifecycle 0.2.2__tar.gz → 0.3.0__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.2
3
+ Version: 0.3.0
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.2"
3
+ version = "0.3.0"
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.2"
3
+ version = "0.3.0"
4
4
  description = "dishka lifecycle support"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -1,5 +1,8 @@
1
1
  import ashka_lifecycle.async_container
2
2
  import ashka_lifecycle.container
3
+ import ashka_lifecycle.provider
4
+ import ashka_lifecycle.provider.make_factory
5
+ import ashka_lifecycle.provider.provider
3
6
  from ashka_lifecycle.entities.scope import AshkaScope
4
7
  from ashka_lifecycle.provider import (
5
8
  provide, # pyright: ignore[reportUnknownVariableType]
@@ -20,3 +23,5 @@ def activate_lifecycle() -> None:
20
23
  """
21
24
  ashka_lifecycle.container.activate()
22
25
  ashka_lifecycle.async_container.activate()
26
+ ashka_lifecycle.provider.provider.activate()
27
+ ashka_lifecycle.provider.make_factory.activate()
@@ -0,0 +1,7 @@
1
+ from dishka import BaseScope, new_scope
2
+
3
+ __all__ = ["AshkaScope"]
4
+
5
+
6
+ class AshkaScope(BaseScope):
7
+ BOOTSTRAP = new_scope("BOOTSTRAP")
@@ -0,0 +1,124 @@
1
+ # type: ignore
2
+ from collections.abc import Callable
3
+ from inspect import isbuiltin, isclass, isfunction
4
+ from logging import getLogger
5
+ from typing import Any, NewType, get_origin, get_type_hints, overload
6
+
7
+ from ashka_lifecycle.entities.bootstrap import (
8
+ bootstrap_types,
9
+ )
10
+ from ashka_lifecycle.entities.scope import AshkaScope
11
+
12
+ from dishka import AnyOf, BaseScope, Scope
13
+ from dishka import provide as _provide
14
+ from dishka.dependency_source.composite import CompositeDependencySource
15
+ from dishka.provider.exceptions import MissingReturnHintError
16
+ from dishka.provider.make_factory import (
17
+ ProvideSource,
18
+ _clean_result_hint,
19
+ _guess_factory_type,
20
+ )
21
+
22
+ __all__: list[str] = ["provide"]
23
+
24
+ _logger = getLogger(__name__)
25
+
26
+
27
+ def activate(): ...
28
+
29
+
30
+
31
+ @overload
32
+ def provide(
33
+ *, scope: BaseScope | AshkaScope | None = None, **kwargs: Any
34
+ ) -> Callable[[Callable[..., Any]], CompositeDependencySource]: ...
35
+
36
+
37
+ @overload
38
+ def provide(
39
+ source: ProvideSource,
40
+ *,
41
+ scope: BaseScope | AshkaScope | None = None,
42
+ **kwargs: Any,
43
+ ) -> CompositeDependencySource: ...
44
+
45
+
46
+ def provide(
47
+ source: ProvideSource | None = None,
48
+ *,
49
+ scope: BaseScope | AshkaScope | None = None,
50
+ **kwargs: Any,
51
+ ) -> (
52
+ CompositeDependencySource
53
+ | Callable[
54
+ [Callable[..., Any]],
55
+ CompositeDependencySource,
56
+ ]
57
+ ):
58
+ return (
59
+ _provide(source, scope=scope, **kwargs)
60
+ if scope is not AshkaScope.BOOTSTRAP
61
+ else (
62
+ scoped
63
+ if (
64
+ scoped := (
65
+ lambda source: (
66
+ _provide(
67
+ source,
68
+ scope=Scope.APP,
69
+ provides=AnyOf[
70
+ NewType_, (_kwargs := kwargs.copy()).pop(provides)
71
+ ],
72
+ **_kwargs,
73
+ )
74
+ if bootstrap_types.add(
75
+ NewType_ := NewType(
76
+ "ashka_lifecycle.provider.make_factory.provide",
77
+ AshkaScope,
78
+ )
79
+ )
80
+ is None
81
+ and _logger.debug(
82
+ f"Adding {getattr(source, '__name__', source)!r} to bootstrap list..."
83
+ )
84
+ is None
85
+ and (provides := "provides") in kwargs
86
+ else _provide(
87
+ source,
88
+ scope=Scope.APP,
89
+ provides=AnyOf[
90
+ NewType_,
91
+ source
92
+ if isclass(source) or isclass(get_origin(source))
93
+ else _clean_result_hint(
94
+ _guess_factory_type(
95
+ func := getattr(source, "__func__", None)
96
+ or (
97
+ source
98
+ if isfunction(source) or isbuiltin(source)
99
+ else getattr(
100
+ source.__call__,
101
+ "__func__",
102
+ source.__call__,
103
+ )
104
+ )
105
+ ),
106
+ type_hints[return_]
107
+ if (return_ := "return")
108
+ in (type_hints := get_type_hints(func))
109
+ or bootstrap_types.remove(NewType_) is not None
110
+ else (_ for _ in ()).throw(
111
+ MissingReturnHintError(source)
112
+ ),
113
+ ),
114
+ ],
115
+ **kwargs,
116
+ )
117
+ )
118
+ )
119
+ )
120
+ is not None
121
+ and source is None
122
+ else scoped(source)
123
+ )
124
+ )
@@ -0,0 +1,131 @@
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
+ import dishka
12
+ from dishka import AnyOf, BaseScope, Scope
13
+ from dishka import provide as _provide # pyright: ignore[reportUnknownVariableType]
14
+ from dishka.dependency_source.composite import CompositeDependencySource
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
+
58
+ is_bootstrap = scope is AshkaScope.BOOTSTRAP
59
+
60
+ def scoped(source: Any) -> CompositeDependencySource:
61
+ _logger.debug(
62
+ f"Adding {getattr(source, '__name__', source)!r} to bootstrap list..."
63
+ )
64
+
65
+ bootstrap_type = NewType(
66
+ "bootstrap_type",
67
+ AshkaScope,
68
+ )
69
+ if is_bootstrap:
70
+ bootstrap_types.add(bootstrap_type)
71
+
72
+ provides = "provides"
73
+
74
+ if provides in kwargs:
75
+ _kwargs = kwargs.copy()
76
+
77
+ _provides = _kwargs.pop(provides)
78
+
79
+ return _provide(
80
+ source,
81
+ scope=Scope.APP if is_bootstrap else scope,
82
+ provides=AnyOf[bootstrap_type, _provides],
83
+ **_kwargs,
84
+ )
85
+
86
+ if isclass(source) or isclass(get_origin(source)):
87
+ return _provide(
88
+ source,
89
+ scope=Scope.APP if is_bootstrap else scope,
90
+ provides=AnyOf[bootstrap_type, source],
91
+ **kwargs,
92
+ )
93
+
94
+ return_ = "return"
95
+
96
+ if isfunction(source) or isbuiltin(source):
97
+ func = source
98
+
99
+ elif hasattr(source, "__func__"):
100
+ func = source.__func__
101
+
102
+ else:
103
+ func = getattr(source.__call__, "__func__", source.__call__)
104
+
105
+ factory_type = _guess_factory_type(func)
106
+
107
+ type_hints = get_type_hints(func)
108
+
109
+ if return_ not in type_hints:
110
+ raise MissingReturnHintError(source)
111
+
112
+ possible_dependency = type_hints[return_]
113
+
114
+ type_hint = _clean_result_hint(factory_type, possible_dependency)
115
+
116
+ return _provide(
117
+ source,
118
+ scope=Scope.APP if is_bootstrap else scope,
119
+ provides=AnyOf[bootstrap_type, type_hint],
120
+ **kwargs,
121
+ )
122
+
123
+ if source is None:
124
+ return scoped
125
+
126
+ return scoped(source)
127
+
128
+
129
+ dishka.provide = dishka.provider.provide = dishka.provider.make_factory.provide = (
130
+ provide
131
+ )
@@ -0,0 +1,42 @@
1
+ from collections.abc import Callable
2
+ from functools import wraps
3
+ from typing import Any
4
+
5
+ from ashka_lifecycle.entities.bootstrap import bootstrap_types
6
+ from ashka_lifecycle.entities.scope import AshkaScope
7
+
8
+ from dishka import Provider, Scope
9
+ from dishka.dependency_source import CompositeDependencySource
10
+
11
+
12
+ def activate(): ...
13
+
14
+
15
+ def __init__(__init__: Callable[..., None]) -> Callable[..., None]:
16
+ @wraps(__init__)
17
+ def inner(self: Provider, *args: Any, **kwargs: Any):
18
+ is_bootstrap = False
19
+ args_ = kwargs_ = None
20
+ if args and args[0] is AshkaScope.BOOTSTRAP:
21
+ args_ = (Scope.APP,) + args[1:]
22
+ is_bootstrap = True
23
+ elif kwargs.get("scope", None) is AshkaScope.BOOTSTRAP:
24
+ (kwargs_ := kwargs.copy())["scope"] = Scope.APP
25
+ is_bootstrap = True
26
+ elif self.scope is AshkaScope.BOOTSTRAP:
27
+ self.scope = Scope.APP
28
+ is_bootstrap = True
29
+
30
+ if is_bootstrap:
31
+ for v in type(self).__dict__.values():
32
+ if (
33
+ isinstance(v, CompositeDependencySource)
34
+ and not v.dependency_sources[1].scope # pyright: ignore[reportAttributeAccessIssue, reportUnknownMemberType]
35
+ ):
36
+ bootstrap_types.add(v.dependency_sources[1].provides.type_hint) # pyright: ignore[reportUnknownMemberType, reportUnknownArgumentType, reportAttributeAccessIssue]
37
+ return __init__(self, *(args_ or args), **(kwargs_ or kwargs))
38
+
39
+ return inner
40
+
41
+
42
+ Provider.__init__ = __init__(Provider.__init__)
@@ -1,7 +0,0 @@
1
- from enum import Enum
2
-
3
- __all__ = ["AshkaScope"]
4
-
5
-
6
- class AshkaScope(Enum):
7
- BOOTSTRAP = "BOOTSTRAP"
@@ -1,110 +0,0 @@
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]