python-injection 0.11.0__tar.gz → 0.12.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.
- {python_injection-0.11.0 → python_injection-0.12.0}/PKG-INFO +9 -12
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/__init__.py +8 -9
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/__init__.pyi +48 -13
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/_core/__init__.py +1 -1
 - python_injection-0.12.0/injection/_core/common/asynchronous.py +54 -0
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/_core/common/invertible.py +2 -2
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/_core/common/type.py +2 -5
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/_core/descriptors.py +3 -3
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/_core/hook.py +13 -10
 - python_injection-0.12.0/injection/_core/injectables.py +106 -0
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/_core/module.py +260 -145
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/integrations/fastapi.py +17 -12
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/testing/__init__.pyi +1 -1
 - {python_injection-0.11.0 → python_injection-0.12.0}/pyproject.toml +11 -10
 - python_injection-0.11.0/injection/integrations/blacksheep.py +0 -34
 - {python_injection-0.11.0 → python_injection-0.12.0}/README.md +0 -0
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/_core/common/__init__.py +0 -0
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/_core/common/event.py +0 -0
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/_core/common/lazy.py +0 -0
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/_core/common/threading.py +0 -0
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/exceptions.py +0 -0
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/integrations/__init__.py +0 -0
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/py.typed +0 -0
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/testing/__init__.py +0 -0
 - {python_injection-0.11.0 → python_injection-0.12.0}/injection/utils.py +0 -0
 
| 
         @@ -1,26 +1,23 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            Metadata-Version: 2. 
     | 
| 
      
 1 
     | 
    
         
            +
            Metadata-Version: 2.3
         
     | 
| 
       2 
2 
     | 
    
         
             
            Name: python-injection
         
     | 
| 
       3 
     | 
    
         
            -
            Version: 0. 
     | 
| 
      
 3 
     | 
    
         
            +
            Version: 0.12.0
         
     | 
| 
       4 
4 
     | 
    
         
             
            Summary: Fast and easy dependency injection framework.
         
     | 
| 
       5 
5 
     | 
    
         
             
            Home-page: https://github.com/100nm/python-injection
         
     | 
| 
       6 
6 
     | 
    
         
             
            License: MIT
         
     | 
| 
       7 
7 
     | 
    
         
             
            Keywords: dependencies,dependency,inject,injection
         
     | 
| 
       8 
8 
     | 
    
         
             
            Author: remimd
         
     | 
| 
       9 
     | 
    
         
            -
            Requires-Python: >=3.12 
     | 
| 
      
 9 
     | 
    
         
            +
            Requires-Python: >=3.12, <4
         
     | 
| 
       10 
10 
     | 
    
         
             
            Classifier: Development Status :: 4 - Beta
         
     | 
| 
       11 
     | 
    
         
            -
            Classifier: Intended Audience :: Developers
         
     | 
| 
       12 
     | 
    
         
            -
            Classifier: License :: OSI Approved :: MIT License
         
     | 
| 
       13 
     | 
    
         
            -
            Classifier: Natural Language :: English
         
     | 
| 
       14 
     | 
    
         
            -
            Classifier: Operating System :: OS Independent
         
     | 
| 
       15 
     | 
    
         
            -
            Classifier: Programming Language :: Python
         
     | 
| 
       16 
     | 
    
         
            -
            Classifier: Programming Language :: Python :: 3
         
     | 
| 
       17 
     | 
    
         
            -
            Classifier: Programming Language :: Python :: 3.12
         
     | 
| 
       18 
     | 
    
         
            -
            Classifier: Programming Language :: Python :: 3.13
         
     | 
| 
       19 
     | 
    
         
            -
            Classifier: Programming Language :: Python :: 3 :: Only
         
     | 
| 
       20 
11 
     | 
    
         
             
            Classifier: Topic :: Software Development :: Libraries
         
     | 
| 
       21 
12 
     | 
    
         
             
            Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
         
     | 
| 
       22 
13 
     | 
    
         
             
            Classifier: Topic :: Software Development :: Libraries :: Python Modules
         
     | 
| 
       23 
14 
     | 
    
         
             
            Classifier: Topic :: Software Development :: Testing
         
     | 
| 
      
 15 
     | 
    
         
            +
            Classifier: Programming Language :: Python
         
     | 
| 
      
 16 
     | 
    
         
            +
            Classifier: Programming Language :: Python :: 3
         
     | 
| 
      
 17 
     | 
    
         
            +
            Classifier: Programming Language :: Python :: 3 :: Only
         
     | 
| 
      
 18 
     | 
    
         
            +
            Classifier: Operating System :: OS Independent
         
     | 
| 
      
 19 
     | 
    
         
            +
            Classifier: Intended Audience :: Developers
         
     | 
| 
      
 20 
     | 
    
         
            +
            Classifier: Natural Language :: English
         
     | 
| 
       24 
21 
     | 
    
         
             
            Classifier: Typing :: Typed
         
     | 
| 
       25 
22 
     | 
    
         
             
            Project-URL: Repository, https://github.com/100nm/python-injection
         
     | 
| 
       26 
23 
     | 
    
         
             
            Description-Content-Type: text/markdown
         
     | 
| 
         @@ -1,5 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            from ._core.descriptors import LazyInstance
         
     | 
| 
       2 
     | 
    
         
            -
            from ._core. 
     | 
| 
      
 2 
     | 
    
         
            +
            from ._core.injectables import Injectable
         
     | 
| 
      
 3 
     | 
    
         
            +
            from ._core.module import Mode, Module, Priority, mod
         
     | 
| 
       3 
4 
     | 
    
         | 
| 
       4 
5 
     | 
    
         
             
            __all__ = (
         
     | 
| 
       5 
6 
     | 
    
         
             
                "Injectable",
         
     | 
| 
         @@ -7,6 +8,9 @@ __all__ = ( 
     | 
|
| 
       7 
8 
     | 
    
         
             
                "Mode",
         
     | 
| 
       8 
9 
     | 
    
         
             
                "Module",
         
     | 
| 
       9 
10 
     | 
    
         
             
                "Priority",
         
     | 
| 
      
 11 
     | 
    
         
            +
                "afind_instance",
         
     | 
| 
      
 12 
     | 
    
         
            +
                "aget_instance",
         
     | 
| 
      
 13 
     | 
    
         
            +
                "aget_lazy_instance",
         
     | 
| 
       10 
14 
     | 
    
         
             
                "constant",
         
     | 
| 
       11 
15 
     | 
    
         
             
                "find_instance",
         
     | 
| 
       12 
16 
     | 
    
         
             
                "get_instance",
         
     | 
| 
         @@ -19,14 +23,9 @@ __all__ = ( 
     | 
|
| 
       19 
23 
     | 
    
         
             
                "singleton",
         
     | 
| 
       20 
24 
     | 
    
         
             
            )
         
     | 
| 
       21 
25 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                    return Module.default()
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
                return Module.from_name(name)
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 26 
     | 
    
         
            +
            afind_instance = mod().afind_instance
         
     | 
| 
      
 27 
     | 
    
         
            +
            aget_instance = mod().aget_instance
         
     | 
| 
      
 28 
     | 
    
         
            +
            aget_lazy_instance = mod().aget_lazy_instance
         
     | 
| 
       30 
29 
     | 
    
         
             
            constant = mod().constant
         
     | 
| 
       31 
30 
     | 
    
         
             
            find_instance = mod().find_instance
         
     | 
| 
       32 
31 
     | 
    
         
             
            get_instance = mod().get_instance
         
     | 
| 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            from abc import abstractmethod
         
     | 
| 
       2 
     | 
    
         
            -
            from collections.abc import Callable
         
     | 
| 
      
 2 
     | 
    
         
            +
            from collections.abc import Awaitable, Callable
         
     | 
| 
       3 
3 
     | 
    
         
             
            from contextlib import ContextDecorator
         
     | 
| 
       4 
4 
     | 
    
         
             
            from enum import Enum
         
     | 
| 
       5 
5 
     | 
    
         
             
            from logging import Logger
         
     | 
| 
         @@ -21,6 +21,9 @@ from ._core.module import ModeStr, PriorityStr 
     | 
|
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
            _: Module = ...
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
      
 24 
     | 
    
         
            +
            afind_instance = _.afind_instance
         
     | 
| 
      
 25 
     | 
    
         
            +
            aget_instance = _.aget_instance
         
     | 
| 
      
 26 
     | 
    
         
            +
            aget_lazy_instance = _.aget_lazy_instance
         
     | 
| 
       24 
27 
     | 
    
         
             
            constant = _.constant
         
     | 
| 
       25 
28 
     | 
    
         
             
            find_instance = _.find_instance
         
     | 
| 
       26 
29 
     | 
    
         
             
            get_instance = _.get_instance
         
     | 
| 
         @@ -53,59 +56,59 @@ class Module: 
     | 
|
| 
       53 
56 
     | 
    
         
             
                def __contains__(self, cls: _InputType[Any], /) -> bool: ...
         
     | 
| 
       54 
57 
     | 
    
         
             
                @property
         
     | 
| 
       55 
58 
     | 
    
         
             
                def is_locked(self) -> bool: ...
         
     | 
| 
       56 
     | 
    
         
            -
                def inject[**P, T](self, wrapped: Callable[P, T] = ..., /) 
     | 
| 
      
 59 
     | 
    
         
            +
                def inject[**P, T](self, wrapped: Callable[P, T] = ..., /) -> Any:
         
     | 
| 
       57 
60 
     | 
    
         
             
                    """
         
     | 
| 
       58 
61 
     | 
    
         
             
                    Decorator applicable to a class or function. Inject function dependencies using
         
     | 
| 
       59 
62 
     | 
    
         
             
                    parameter type annotations. If applied to a class, the dependencies resolved
         
     | 
| 
       60 
63 
     | 
    
         
             
                    will be those of the `__init__` method.
         
     | 
| 
       61 
64 
     | 
    
         
             
                    """
         
     | 
| 
       62 
65 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
                def injectable[**P, T]( 
     | 
| 
      
 66 
     | 
    
         
            +
                def injectable[**P, T](
         
     | 
| 
       64 
67 
     | 
    
         
             
                    self,
         
     | 
| 
       65 
     | 
    
         
            -
                    wrapped: Callable[P, T] = ...,
         
     | 
| 
      
 68 
     | 
    
         
            +
                    wrapped: Callable[P, T] | Callable[P, Awaitable[T]] = ...,
         
     | 
| 
       66 
69 
     | 
    
         
             
                    /,
         
     | 
| 
       67 
70 
     | 
    
         
             
                    *,
         
     | 
| 
       68 
71 
     | 
    
         
             
                    cls: _InjectableFactory[T] = ...,
         
     | 
| 
       69 
72 
     | 
    
         
             
                    inject: bool = ...,
         
     | 
| 
       70 
73 
     | 
    
         
             
                    on: _TypeInfo[T] = ...,
         
     | 
| 
       71 
74 
     | 
    
         
             
                    mode: Mode | ModeStr = ...,
         
     | 
| 
       72 
     | 
    
         
            -
                ):
         
     | 
| 
      
 75 
     | 
    
         
            +
                ) -> Any:
         
     | 
| 
       73 
76 
     | 
    
         
             
                    """
         
     | 
| 
       74 
77 
     | 
    
         
             
                    Decorator applicable to a class or function. It is used to indicate how the
         
     | 
| 
       75 
78 
     | 
    
         
             
                    injectable will be constructed. At injection time, a new instance will be
         
     | 
| 
       76 
79 
     | 
    
         
             
                    injected each time.
         
     | 
| 
       77 
80 
     | 
    
         
             
                    """
         
     | 
| 
       78 
81 
     | 
    
         | 
| 
       79 
     | 
    
         
            -
                def singleton[**P, T]( 
     | 
| 
      
 82 
     | 
    
         
            +
                def singleton[**P, T](
         
     | 
| 
       80 
83 
     | 
    
         
             
                    self,
         
     | 
| 
       81 
     | 
    
         
            -
                    wrapped: Callable[P, T] = ...,
         
     | 
| 
      
 84 
     | 
    
         
            +
                    wrapped: Callable[P, T] | Callable[P, Awaitable[T]] = ...,
         
     | 
| 
       82 
85 
     | 
    
         
             
                    /,
         
     | 
| 
       83 
86 
     | 
    
         
             
                    *,
         
     | 
| 
       84 
87 
     | 
    
         
             
                    inject: bool = ...,
         
     | 
| 
       85 
88 
     | 
    
         
             
                    on: _TypeInfo[T] = ...,
         
     | 
| 
       86 
89 
     | 
    
         
             
                    mode: Mode | ModeStr = ...,
         
     | 
| 
       87 
     | 
    
         
            -
                ):
         
     | 
| 
      
 90 
     | 
    
         
            +
                ) -> Any:
         
     | 
| 
       88 
91 
     | 
    
         
             
                    """
         
     | 
| 
       89 
92 
     | 
    
         
             
                    Decorator applicable to a class or function. It is used to indicate how the
         
     | 
| 
       90 
93 
     | 
    
         
             
                    singleton will be constructed. At injection time, the injected instance will
         
     | 
| 
       91 
94 
     | 
    
         
             
                    always be the same.
         
     | 
| 
       92 
95 
     | 
    
         
             
                    """
         
     | 
| 
       93 
96 
     | 
    
         | 
| 
       94 
     | 
    
         
            -
                def should_be_injectable[T](self, wrapped: type[T] = ..., /) 
     | 
| 
      
 97 
     | 
    
         
            +
                def should_be_injectable[T](self, wrapped: type[T] = ..., /) -> Any:
         
     | 
| 
       95 
98 
     | 
    
         
             
                    """
         
     | 
| 
       96 
99 
     | 
    
         
             
                    Decorator applicable to a class. It is used to specify whether an injectable
         
     | 
| 
       97 
100 
     | 
    
         
             
                    should be registered. Raise an exception at injection time if the class isn't
         
     | 
| 
       98 
101 
     | 
    
         
             
                    registered.
         
     | 
| 
       99 
102 
     | 
    
         
             
                    """
         
     | 
| 
       100 
103 
     | 
    
         | 
| 
       101 
     | 
    
         
            -
                def constant[T]( 
     | 
| 
      
 104 
     | 
    
         
            +
                def constant[T](
         
     | 
| 
       102 
105 
     | 
    
         
             
                    self,
         
     | 
| 
       103 
106 
     | 
    
         
             
                    wrapped: type[T] = ...,
         
     | 
| 
       104 
107 
     | 
    
         
             
                    /,
         
     | 
| 
       105 
108 
     | 
    
         
             
                    *,
         
     | 
| 
       106 
109 
     | 
    
         
             
                    on: _TypeInfo[T] = ...,
         
     | 
| 
       107 
110 
     | 
    
         
             
                    mode: Mode | ModeStr = ...,
         
     | 
| 
       108 
     | 
    
         
            -
                ):
         
     | 
| 
      
 111 
     | 
    
         
            +
                ) -> Any:
         
     | 
| 
       109 
112 
     | 
    
         
             
                    """
         
     | 
| 
       110 
113 
     | 
    
         
             
                    Decorator applicable to a class or function. It is used to indicate how the
         
     | 
| 
       111 
114 
     | 
    
         
             
                    constant is constructed. At injection time, the injected instance will always
         
     | 
| 
         @@ -131,12 +134,25 @@ class Module: 
     | 
|
| 
       131 
134 
     | 
    
         
             
                    wrapped: Callable[P, T],
         
     | 
| 
       132 
135 
     | 
    
         
             
                    /,
         
     | 
| 
       133 
136 
     | 
    
         
             
                ) -> Callable[P, T]: ...
         
     | 
| 
      
 137 
     | 
    
         
            +
                async def afind_instance[T](self, cls: _InputType[T]) -> T: ...
         
     | 
| 
       134 
138 
     | 
    
         
             
                def find_instance[T](self, cls: _InputType[T]) -> T:
         
     | 
| 
       135 
139 
     | 
    
         
             
                    """
         
     | 
| 
       136 
140 
     | 
    
         
             
                    Function used to retrieve an instance associated with the type passed in
         
     | 
| 
       137 
141 
     | 
    
         
             
                    parameter or an exception will be raised.
         
     | 
| 
       138 
142 
     | 
    
         
             
                    """
         
     | 
| 
       139 
143 
     | 
    
         | 
| 
      
 144 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 145 
     | 
    
         
            +
                async def aget_instance[T, Default](
         
     | 
| 
      
 146 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 147 
     | 
    
         
            +
                    cls: _InputType[T],
         
     | 
| 
      
 148 
     | 
    
         
            +
                    default: Default,
         
     | 
| 
      
 149 
     | 
    
         
            +
                ) -> T | Default: ...
         
     | 
| 
      
 150 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 151 
     | 
    
         
            +
                async def aget_instance[T](
         
     | 
| 
      
 152 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 153 
     | 
    
         
            +
                    cls: _InputType[T],
         
     | 
| 
      
 154 
     | 
    
         
            +
                    default: None = ...,
         
     | 
| 
      
 155 
     | 
    
         
            +
                ) -> T | None: ...
         
     | 
| 
       140 
156 
     | 
    
         
             
                @overload
         
     | 
| 
       141 
157 
     | 
    
         
             
                def get_instance[T, Default](
         
     | 
| 
       142 
158 
     | 
    
         
             
                    self,
         
     | 
| 
         @@ -149,12 +165,28 @@ class Module: 
     | 
|
| 
       149 
165 
     | 
    
         
             
                    """
         
     | 
| 
       150 
166 
     | 
    
         | 
| 
       151 
167 
     | 
    
         
             
                @overload
         
     | 
| 
       152 
     | 
    
         
            -
                def get_instance[T 
     | 
| 
      
 168 
     | 
    
         
            +
                def get_instance[T](
         
     | 
| 
       153 
169 
     | 
    
         
             
                    self,
         
     | 
| 
       154 
170 
     | 
    
         
             
                    cls: _InputType[T],
         
     | 
| 
       155 
171 
     | 
    
         
             
                    default: None = ...,
         
     | 
| 
       156 
172 
     | 
    
         
             
                ) -> T | None: ...
         
     | 
| 
       157 
173 
     | 
    
         
             
                @overload
         
     | 
| 
      
 174 
     | 
    
         
            +
                def aget_lazy_instance[T, Default](
         
     | 
| 
      
 175 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 176 
     | 
    
         
            +
                    cls: _InputType[T],
         
     | 
| 
      
 177 
     | 
    
         
            +
                    default: Default,
         
     | 
| 
      
 178 
     | 
    
         
            +
                    *,
         
     | 
| 
      
 179 
     | 
    
         
            +
                    cache: bool = ...,
         
     | 
| 
      
 180 
     | 
    
         
            +
                ) -> Awaitable[T | Default]: ...
         
     | 
| 
      
 181 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 182 
     | 
    
         
            +
                def aget_lazy_instance[T](
         
     | 
| 
      
 183 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 184 
     | 
    
         
            +
                    cls: _InputType[T],
         
     | 
| 
      
 185 
     | 
    
         
            +
                    default: None = ...,
         
     | 
| 
      
 186 
     | 
    
         
            +
                    *,
         
     | 
| 
      
 187 
     | 
    
         
            +
                    cache: bool = ...,
         
     | 
| 
      
 188 
     | 
    
         
            +
                ) -> Awaitable[T | None]: ...
         
     | 
| 
      
 189 
     | 
    
         
            +
                @overload
         
     | 
| 
       158 
190 
     | 
    
         
             
                def get_lazy_instance[T, Default](
         
     | 
| 
       159 
191 
     | 
    
         
             
                    self,
         
     | 
| 
       160 
192 
     | 
    
         
             
                    cls: _InputType[T],
         
     | 
| 
         @@ -172,7 +204,7 @@ class Module: 
     | 
|
| 
       172 
204 
     | 
    
         
             
                    """
         
     | 
| 
       173 
205 
     | 
    
         | 
| 
       174 
206 
     | 
    
         
             
                @overload
         
     | 
| 
       175 
     | 
    
         
            -
                def get_lazy_instance[T 
     | 
| 
      
 207 
     | 
    
         
            +
                def get_lazy_instance[T](
         
     | 
| 
       176 
208 
     | 
    
         
             
                    self,
         
     | 
| 
       177 
209 
     | 
    
         
             
                    cls: _InputType[T],
         
     | 
| 
       178 
210 
     | 
    
         
             
                    default: None = ...,
         
     | 
| 
         @@ -229,6 +261,7 @@ class Module: 
     | 
|
| 
       229 
261 
     | 
    
         
             
                    Function to unlock the module by deleting cached instances of singletons.
         
     | 
| 
       230 
262 
     | 
    
         
             
                    """
         
     | 
| 
       231 
263 
     | 
    
         | 
| 
      
 264 
     | 
    
         
            +
                async def all_ready(self) -> None: ...
         
     | 
| 
       232 
265 
     | 
    
         
             
                def add_logger(self, logger: Logger) -> Self: ...
         
     | 
| 
       233 
266 
     | 
    
         
             
                @classmethod
         
     | 
| 
       234 
267 
     | 
    
         
             
                def from_name(cls, name: str) -> Module:
         
     | 
| 
         @@ -253,6 +286,8 @@ class Injectable[T](Protocol): 
     | 
|
| 
       253 
286 
     | 
    
         
             
                def is_locked(self) -> bool: ...
         
     | 
| 
       254 
287 
     | 
    
         
             
                def unlock(self) -> None: ...
         
     | 
| 
       255 
288 
     | 
    
         
             
                @abstractmethod
         
     | 
| 
      
 289 
     | 
    
         
            +
                async def aget_instance(self) -> T: ...
         
     | 
| 
      
 290 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
       256 
291 
     | 
    
         
             
                def get_instance(self) -> T: ...
         
     | 
| 
       257 
292 
     | 
    
         | 
| 
       258 
293 
     | 
    
         
             
            @final
         
     | 
| 
         @@ -49,5 +49,5 @@ def standardize_input_classes[T]( 
     | 
|
| 
       49 
49 
     | 
    
         
             
            @Locator.static_hooks.on_update
         
     | 
| 
       50 
50 
     | 
    
         
             
            def standardize_classes[T](*_: Any, **__: Any) -> HookGenerator[Updater[T]]:
         
     | 
| 
       51 
51 
     | 
    
         
             
                updater = yield
         
     | 
| 
       52 
     | 
    
         
            -
                updater.classes =  
     | 
| 
      
 52 
     | 
    
         
            +
                updater.classes = frozenset(standardize_types(*updater.classes))
         
     | 
| 
       53 
53 
     | 
    
         
             
                return updater
         
     | 
| 
         @@ -0,0 +1,54 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            from abc import abstractmethod
         
     | 
| 
      
 2 
     | 
    
         
            +
            from collections.abc import Awaitable, Callable, Generator
         
     | 
| 
      
 3 
     | 
    
         
            +
            from dataclasses import dataclass
         
     | 
| 
      
 4 
     | 
    
         
            +
            from typing import Any, NoReturn, Protocol, override, runtime_checkable
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            @dataclass(repr=False, eq=False, frozen=True, slots=True)
         
     | 
| 
      
 8 
     | 
    
         
            +
            class SimpleAwaitable[T](Awaitable[T]):
         
     | 
| 
      
 9 
     | 
    
         
            +
                callable: Callable[..., Awaitable[T]]
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                @override
         
     | 
| 
      
 12 
     | 
    
         
            +
                def __await__(self) -> Generator[Any, Any, T]:
         
     | 
| 
      
 13 
     | 
    
         
            +
                    return self.callable().__await__()
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            @runtime_checkable
         
     | 
| 
      
 17 
     | 
    
         
            +
            class Caller[**P, T](Protocol):
         
     | 
| 
      
 18 
     | 
    
         
            +
                __slots__ = ()
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
      
 21 
     | 
    
         
            +
                async def acall(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
      
 22 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
      
 25 
     | 
    
         
            +
                def call(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
      
 26 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            @dataclass(repr=False, eq=False, frozen=True, slots=True)
         
     | 
| 
      
 30 
     | 
    
         
            +
            class AsyncCaller[**P, T](Caller[P, T]):
         
     | 
| 
      
 31 
     | 
    
         
            +
                callable: Callable[P, Awaitable[T]]
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                @override
         
     | 
| 
      
 34 
     | 
    
         
            +
                async def acall(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
      
 35 
     | 
    
         
            +
                    return await self.callable(*args, **kwargs)
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                @override
         
     | 
| 
      
 38 
     | 
    
         
            +
                def call(self, /, *args: P.args, **kwargs: P.kwargs) -> NoReturn:
         
     | 
| 
      
 39 
     | 
    
         
            +
                    raise RuntimeError(
         
     | 
| 
      
 40 
     | 
    
         
            +
                        "Synchronous call isn't supported for an asynchronous Callable."
         
     | 
| 
      
 41 
     | 
    
         
            +
                    )
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            @dataclass(repr=False, eq=False, frozen=True, slots=True)
         
     | 
| 
      
 45 
     | 
    
         
            +
            class SyncCaller[**P, T](Caller[P, T]):
         
     | 
| 
      
 46 
     | 
    
         
            +
                callable: Callable[P, T]
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                @override
         
     | 
| 
      
 49 
     | 
    
         
            +
                async def acall(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
      
 50 
     | 
    
         
            +
                    return self.callable(*args, **kwargs)
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                @override
         
     | 
| 
      
 53 
     | 
    
         
            +
                def call(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
      
 54 
     | 
    
         
            +
                    return self.callable(*args, **kwargs)
         
     | 
| 
         @@ -13,8 +13,8 @@ class Invertible[T](Protocol): 
     | 
|
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
            @dataclass(repr=False, eq=False, frozen=True, slots=True)
         
     | 
| 
       15 
15 
     | 
    
         
             
            class SimpleInvertible[T](Invertible[T]):
         
     | 
| 
       16 
     | 
    
         
            -
                 
     | 
| 
      
 16 
     | 
    
         
            +
                callable: Callable[..., T]
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                @override
         
     | 
| 
       19 
19 
     | 
    
         
             
                def __invert__(self) -> T:
         
     | 
| 
       20 
     | 
    
         
            -
                    return self. 
     | 
| 
      
 20 
     | 
    
         
            +
                    return self.callable()
         
     | 
| 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            from collections.abc import  
     | 
| 
       2 
     | 
    
         
            -
            from inspect import  
     | 
| 
      
 1 
     | 
    
         
            +
            from collections.abc import Callable, Iterable, Iterator
         
     | 
| 
      
 2 
     | 
    
         
            +
            from inspect import isfunction
         
     | 
| 
       3 
3 
     | 
    
         
             
            from types import GenericAlias, UnionType
         
     | 
| 
       4 
4 
     | 
    
         
             
            from typing import (
         
     | 
| 
       5 
5 
     | 
    
         
             
                Annotated,
         
     | 
| 
         @@ -24,9 +24,6 @@ def get_return_types(*args: TypeInfo[Any]) -> Iterator[InputType[Any]]: 
     | 
|
| 
       24 
24 
     | 
    
         
             
                        inner_args = arg
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
                    elif isfunction(arg) and (return_type := get_type_hints(arg).get("return")):
         
     | 
| 
       27 
     | 
    
         
            -
                        if iscoroutinefunction(arg):
         
     | 
| 
       28 
     | 
    
         
            -
                            return_type = Awaitable[return_type]  # type: ignore[valid-type]
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
27 
     | 
    
         
             
                        inner_args = (return_type,)
         
     | 
| 
       31 
28 
     | 
    
         | 
| 
       32 
29 
     | 
    
         
             
                    else:
         
     | 
| 
         @@ -2,7 +2,7 @@ from typing import Self 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            from injection._core.common.invertible import Invertible
         
     | 
| 
       4 
4 
     | 
    
         
             
            from injection._core.common.type import InputType
         
     | 
| 
       5 
     | 
    
         
            -
            from injection._core.module import Module
         
     | 
| 
      
 5 
     | 
    
         
            +
            from injection._core.module import Module, mod
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            class LazyInstance[T]:
         
     | 
| 
         @@ -11,8 +11,8 @@ class LazyInstance[T]: 
     | 
|
| 
       11 
11 
     | 
    
         
             
                __value: Invertible[T]
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
                def __init__(self, cls: InputType[T], module: Module | None = None) -> None:
         
     | 
| 
       14 
     | 
    
         
            -
                    module = module or  
     | 
| 
       15 
     | 
    
         
            -
                    self.__value = module.get_lazy_instance(cls, default=NotImplemented) 
     | 
| 
      
 14 
     | 
    
         
            +
                    module = module or mod()
         
     | 
| 
      
 15 
     | 
    
         
            +
                    self.__value = module.get_lazy_instance(cls, default=NotImplemented)
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
                def __get__(
         
     | 
| 
       18 
18 
     | 
    
         
             
                    self,
         
     | 
| 
         @@ -2,12 +2,13 @@ import itertools 
     | 
|
| 
       2 
2 
     | 
    
         
             
            from collections.abc import Callable, Generator, Iterator
         
     | 
| 
       3 
3 
     | 
    
         
             
            from dataclasses import dataclass, field
         
     | 
| 
       4 
4 
     | 
    
         
             
            from inspect import isclass, isgeneratorfunction
         
     | 
| 
       5 
     | 
    
         
            -
            from typing import Any, Self
         
     | 
| 
      
 5 
     | 
    
         
            +
            from typing import Any, Self, TypeGuard
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            from injection.exceptions import HookError
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
            type HookGenerator[T] = Generator[None, T, T]
         
     | 
| 
       10 
     | 
    
         
            -
            type  
     | 
| 
      
 10 
     | 
    
         
            +
            type HookGeneratorFunction[**P, T] = Callable[P, HookGenerator[T]]
         
     | 
| 
      
 11 
     | 
    
         
            +
            type HookFunction[**P, T] = Callable[P, T] | HookGeneratorFunction[P, T]
         
     | 
| 
       11 
12 
     | 
    
         | 
| 
       12 
13 
     | 
    
         | 
| 
       13 
14 
     | 
    
         
             
            @dataclass(eq=False, frozen=True, slots=True)
         
     | 
| 
         @@ -18,12 +19,12 @@ class Hook[**P, T]: 
     | 
|
| 
       18 
19 
     | 
    
         
             
                    repr=False,
         
     | 
| 
       19 
20 
     | 
    
         
             
                )
         
     | 
| 
       20 
21 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
                def __call__( 
     | 
| 
      
 22 
     | 
    
         
            +
                def __call__(
         
     | 
| 
       22 
23 
     | 
    
         
             
                    self,
         
     | 
| 
       23 
24 
     | 
    
         
             
                    wrapped: HookFunction[P, T] | type[HookFunction[P, T]] | None = None,
         
     | 
| 
       24 
25 
     | 
    
         
             
                    /,
         
     | 
| 
       25 
     | 
    
         
            -
                ):
         
     | 
| 
       26 
     | 
    
         
            -
                    def decorator(wp 
     | 
| 
      
 26 
     | 
    
         
            +
                ) -> Any:
         
     | 
| 
      
 27 
     | 
    
         
            +
                    def decorator(wp: Any) -> Any:
         
     | 
| 
       27 
28 
     | 
    
         
             
                        self.add(wp() if isclass(wp) else wp)
         
     | 
| 
       28 
29 
     | 
    
         
             
                        return wp
         
     | 
| 
       29 
30 
     | 
    
         | 
| 
         @@ -48,11 +49,11 @@ class Hook[**P, T]: 
     | 
|
| 
       48 
49 
     | 
    
         
             
                    handler: Callable[P, T],
         
     | 
| 
       49 
50 
     | 
    
         
             
                    function: HookFunction[P, T],
         
     | 
| 
       50 
51 
     | 
    
         
             
                ) -> Callable[P, T]:
         
     | 
| 
       51 
     | 
    
         
            -
                    if not cls. 
     | 
| 
      
 52 
     | 
    
         
            +
                    if not cls.__is_hook_generator_function(function):
         
     | 
| 
       52 
53 
     | 
    
         
             
                        return function  # type: ignore[return-value]
         
     | 
| 
       53 
54 
     | 
    
         | 
| 
       54 
55 
     | 
    
         
             
                    def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
       55 
     | 
    
         
            -
                        hook: HookGenerator[T] = function(*args, **kwargs) 
     | 
| 
      
 56 
     | 
    
         
            +
                        hook: HookGenerator[T] = function(*args, **kwargs)
         
     | 
| 
       56 
57 
     | 
    
         | 
| 
       57 
58 
     | 
    
         
             
                        try:
         
     | 
| 
       58 
59 
     | 
    
         
             
                            next(hook)
         
     | 
| 
         @@ -88,9 +89,11 @@ class Hook[**P, T]: 
     | 
|
| 
       88 
89 
     | 
    
         
             
                    return handler
         
     | 
| 
       89 
90 
     | 
    
         | 
| 
       90 
91 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       91 
     | 
    
         
            -
                def  
     | 
| 
       92 
     | 
    
         
            -
                     
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
      
 92 
     | 
    
         
            +
                def __is_hook_generator_function[**_P, _T](
         
     | 
| 
      
 93 
     | 
    
         
            +
                    function: HookFunction[_P, _T],
         
     | 
| 
      
 94 
     | 
    
         
            +
                ) -> TypeGuard[HookGeneratorFunction[_P, _T]]:
         
     | 
| 
      
 95 
     | 
    
         
            +
                    for fn in function, getattr(function, "__call__", None):
         
     | 
| 
      
 96 
     | 
    
         
            +
                        if isgeneratorfunction(fn):
         
     | 
| 
       94 
97 
     | 
    
         
             
                            return True
         
     | 
| 
       95 
98 
     | 
    
         | 
| 
       96 
99 
     | 
    
         
             
                    return False
         
     | 
| 
         @@ -0,0 +1,106 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            from abc import ABC, abstractmethod
         
     | 
| 
      
 2 
     | 
    
         
            +
            from collections.abc import MutableMapping
         
     | 
| 
      
 3 
     | 
    
         
            +
            from contextlib import suppress
         
     | 
| 
      
 4 
     | 
    
         
            +
            from dataclasses import dataclass
         
     | 
| 
      
 5 
     | 
    
         
            +
            from typing import Any, ClassVar, NoReturn, Protocol, override, runtime_checkable
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            from injection._core.common.asynchronous import Caller
         
     | 
| 
      
 8 
     | 
    
         
            +
            from injection._core.common.threading import synchronized
         
     | 
| 
      
 9 
     | 
    
         
            +
            from injection.exceptions import InjectionError
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            @runtime_checkable
         
     | 
| 
      
 13 
     | 
    
         
            +
            class Injectable[T](Protocol):
         
     | 
| 
      
 14 
     | 
    
         
            +
                __slots__ = ()
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                @property
         
     | 
| 
      
 17 
     | 
    
         
            +
                def is_locked(self) -> bool:
         
     | 
| 
      
 18 
     | 
    
         
            +
                    return False
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def unlock(self) -> None:
         
     | 
| 
      
 21 
     | 
    
         
            +
                    return
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
      
 24 
     | 
    
         
            +
                async def aget_instance(self) -> T:
         
     | 
| 
      
 25 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
      
 28 
     | 
    
         
            +
                def get_instance(self) -> T:
         
     | 
| 
      
 29 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            @dataclass(repr=False, frozen=True, slots=True)
         
     | 
| 
      
 33 
     | 
    
         
            +
            class BaseInjectable[T](Injectable[T], ABC):
         
     | 
| 
      
 34 
     | 
    
         
            +
                factory: Caller[..., T]
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            class SimpleInjectable[T](BaseInjectable[T]):
         
     | 
| 
      
 38 
     | 
    
         
            +
                __slots__ = ()
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                @override
         
     | 
| 
      
 41 
     | 
    
         
            +
                async def aget_instance(self) -> T:
         
     | 
| 
      
 42 
     | 
    
         
            +
                    return await self.factory.acall()
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                @override
         
     | 
| 
      
 45 
     | 
    
         
            +
                def get_instance(self) -> T:
         
     | 
| 
      
 46 
     | 
    
         
            +
                    return self.factory.call()
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            class SingletonInjectable[T](BaseInjectable[T]):
         
     | 
| 
      
 50 
     | 
    
         
            +
                __slots__ = ("__dict__",)
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                __key: ClassVar[str] = "$instance"
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                @property
         
     | 
| 
      
 55 
     | 
    
         
            +
                def cache(self) -> MutableMapping[str, Any]:
         
     | 
| 
      
 56 
     | 
    
         
            +
                    return self.__dict__
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                @property
         
     | 
| 
      
 59 
     | 
    
         
            +
                @override
         
     | 
| 
      
 60 
     | 
    
         
            +
                def is_locked(self) -> bool:
         
     | 
| 
      
 61 
     | 
    
         
            +
                    return self.__key in self.cache
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                @override
         
     | 
| 
      
 64 
     | 
    
         
            +
                def unlock(self) -> None:
         
     | 
| 
      
 65 
     | 
    
         
            +
                    self.cache.clear()
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                @override
         
     | 
| 
      
 68 
     | 
    
         
            +
                async def aget_instance(self) -> T:
         
     | 
| 
      
 69 
     | 
    
         
            +
                    with suppress(KeyError):
         
     | 
| 
      
 70 
     | 
    
         
            +
                        return self.__check_instance()
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    with synchronized():
         
     | 
| 
      
 73 
     | 
    
         
            +
                        instance = await self.factory.acall()
         
     | 
| 
      
 74 
     | 
    
         
            +
                        self.__set_instance(instance)
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                    return instance
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                @override
         
     | 
| 
      
 79 
     | 
    
         
            +
                def get_instance(self) -> T:
         
     | 
| 
      
 80 
     | 
    
         
            +
                    with suppress(KeyError):
         
     | 
| 
      
 81 
     | 
    
         
            +
                        return self.__check_instance()
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                    with synchronized():
         
     | 
| 
      
 84 
     | 
    
         
            +
                        instance = self.factory.call()
         
     | 
| 
      
 85 
     | 
    
         
            +
                        self.__set_instance(instance)
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                    return instance
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                def __check_instance(self) -> T:
         
     | 
| 
      
 90 
     | 
    
         
            +
                    return self.cache[self.__key]
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                def __set_instance(self, value: T) -> None:
         
     | 
| 
      
 93 
     | 
    
         
            +
                    self.cache[self.__key] = value
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
            @dataclass(repr=False, frozen=True, slots=True)
         
     | 
| 
      
 97 
     | 
    
         
            +
            class ShouldBeInjectable[T](Injectable[T]):
         
     | 
| 
      
 98 
     | 
    
         
            +
                cls: type[T]
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                @override
         
     | 
| 
      
 101 
     | 
    
         
            +
                async def aget_instance(self) -> T:
         
     | 
| 
      
 102 
     | 
    
         
            +
                    return self.get_instance()
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                @override
         
     | 
| 
      
 105 
     | 
    
         
            +
                def get_instance(self) -> NoReturn:
         
     | 
| 
      
 106 
     | 
    
         
            +
                    raise InjectionError(f"`{self.cls}` should be an injectable.")
         
     | 
| 
         @@ -1,21 +1,23 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            from __future__ import annotations
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            import asyncio
         
     | 
| 
       3 
4 
     | 
    
         
             
            import inspect
         
     | 
| 
       4 
5 
     | 
    
         
             
            from abc import ABC, abstractmethod
         
     | 
| 
       5 
6 
     | 
    
         
             
            from collections import OrderedDict
         
     | 
| 
       6 
7 
     | 
    
         
             
            from collections.abc import (
         
     | 
| 
      
 8 
     | 
    
         
            +
                AsyncIterator,
         
     | 
| 
      
 9 
     | 
    
         
            +
                Awaitable,
         
     | 
| 
       7 
10 
     | 
    
         
             
                Callable,
         
     | 
| 
       8 
11 
     | 
    
         
             
                Collection,
         
     | 
| 
       9 
12 
     | 
    
         
             
                Iterable,
         
     | 
| 
       10 
13 
     | 
    
         
             
                Iterator,
         
     | 
| 
       11 
14 
     | 
    
         
             
                Mapping,
         
     | 
| 
       12 
     | 
    
         
            -
                MutableMapping,
         
     | 
| 
       13 
15 
     | 
    
         
             
            )
         
     | 
| 
       14 
16 
     | 
    
         
             
            from contextlib import contextmanager, suppress
         
     | 
| 
       15 
17 
     | 
    
         
             
            from dataclasses import dataclass, field
         
     | 
| 
       16 
18 
     | 
    
         
             
            from enum import StrEnum
         
     | 
| 
       17 
19 
     | 
    
         
             
            from functools import partialmethod, singledispatchmethod, update_wrapper
         
     | 
| 
       18 
     | 
    
         
            -
            from inspect import Signature, isclass
         
     | 
| 
      
 20 
     | 
    
         
            +
            from inspect import Signature, isclass, iscoroutinefunction
         
     | 
| 
       19 
21 
     | 
    
         
             
            from logging import Logger, getLogger
         
     | 
| 
       20 
22 
     | 
    
         
             
            from queue import Empty, Queue
         
     | 
| 
       21 
23 
     | 
    
         
             
            from types import MethodType
         
     | 
| 
         @@ -25,22 +27,34 @@ from typing import ( 
     | 
|
| 
       25 
27 
     | 
    
         
             
                ContextManager,
         
     | 
| 
       26 
28 
     | 
    
         
             
                Literal,
         
     | 
| 
       27 
29 
     | 
    
         
             
                NamedTuple,
         
     | 
| 
       28 
     | 
    
         
            -
                NoReturn,
         
     | 
| 
       29 
30 
     | 
    
         
             
                Protocol,
         
     | 
| 
       30 
31 
     | 
    
         
             
                Self,
         
     | 
| 
      
 32 
     | 
    
         
            +
                TypeGuard,
         
     | 
| 
      
 33 
     | 
    
         
            +
                overload,
         
     | 
| 
       31 
34 
     | 
    
         
             
                override,
         
     | 
| 
       32 
35 
     | 
    
         
             
                runtime_checkable,
         
     | 
| 
       33 
36 
     | 
    
         
             
            )
         
     | 
| 
       34 
37 
     | 
    
         
             
            from uuid import uuid4
         
     | 
| 
       35 
38 
     | 
    
         | 
| 
      
 39 
     | 
    
         
            +
            from injection._core.common.asynchronous import (
         
     | 
| 
      
 40 
     | 
    
         
            +
                AsyncCaller,
         
     | 
| 
      
 41 
     | 
    
         
            +
                Caller,
         
     | 
| 
      
 42 
     | 
    
         
            +
                SimpleAwaitable,
         
     | 
| 
      
 43 
     | 
    
         
            +
                SyncCaller,
         
     | 
| 
      
 44 
     | 
    
         
            +
            )
         
     | 
| 
       36 
45 
     | 
    
         
             
            from injection._core.common.event import Event, EventChannel, EventListener
         
     | 
| 
       37 
46 
     | 
    
         
             
            from injection._core.common.invertible import Invertible, SimpleInvertible
         
     | 
| 
       38 
47 
     | 
    
         
             
            from injection._core.common.lazy import Lazy, LazyMapping
         
     | 
| 
       39 
48 
     | 
    
         
             
            from injection._core.common.threading import synchronized
         
     | 
| 
       40 
49 
     | 
    
         
             
            from injection._core.common.type import InputType, TypeInfo, get_return_types
         
     | 
| 
       41 
50 
     | 
    
         
             
            from injection._core.hook import Hook, apply_hooks
         
     | 
| 
      
 51 
     | 
    
         
            +
            from injection._core.injectables import (
         
     | 
| 
      
 52 
     | 
    
         
            +
                Injectable,
         
     | 
| 
      
 53 
     | 
    
         
            +
                ShouldBeInjectable,
         
     | 
| 
      
 54 
     | 
    
         
            +
                SimpleInjectable,
         
     | 
| 
      
 55 
     | 
    
         
            +
                SingletonInjectable,
         
     | 
| 
      
 56 
     | 
    
         
            +
            )
         
     | 
| 
       42 
57 
     | 
    
         
             
            from injection.exceptions import (
         
     | 
| 
       43 
     | 
    
         
            -
                InjectionError,
         
     | 
| 
       44 
58 
     | 
    
         
             
                ModuleError,
         
     | 
| 
       45 
59 
     | 
    
         
             
                ModuleLockError,
         
     | 
| 
       46 
60 
     | 
    
         
             
                ModuleNotUsedError,
         
     | 
| 
         @@ -129,86 +143,6 @@ class ModulePriorityUpdated(ModuleEvent): 
     | 
|
| 
       129 
143 
     | 
    
         
             
                    )
         
     | 
| 
       130 
144 
     | 
    
         | 
| 
       131 
145 
     | 
    
         | 
| 
       132 
     | 
    
         
            -
            """
         
     | 
| 
       133 
     | 
    
         
            -
            Injectables
         
     | 
| 
       134 
     | 
    
         
            -
            """
         
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
       136 
     | 
    
         
            -
             
     | 
| 
       137 
     | 
    
         
            -
            @runtime_checkable
         
     | 
| 
       138 
     | 
    
         
            -
            class Injectable[T](Protocol):
         
     | 
| 
       139 
     | 
    
         
            -
                __slots__ = ()
         
     | 
| 
       140 
     | 
    
         
            -
             
     | 
| 
       141 
     | 
    
         
            -
                @property
         
     | 
| 
       142 
     | 
    
         
            -
                def is_locked(self) -> bool:
         
     | 
| 
       143 
     | 
    
         
            -
                    return False
         
     | 
| 
       144 
     | 
    
         
            -
             
     | 
| 
       145 
     | 
    
         
            -
                def unlock(self) -> None:
         
     | 
| 
       146 
     | 
    
         
            -
                    return
         
     | 
| 
       147 
     | 
    
         
            -
             
     | 
| 
       148 
     | 
    
         
            -
                @abstractmethod
         
     | 
| 
       149 
     | 
    
         
            -
                def get_instance(self) -> T:
         
     | 
| 
       150 
     | 
    
         
            -
                    raise NotImplementedError
         
     | 
| 
       151 
     | 
    
         
            -
             
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
            @dataclass(repr=False, frozen=True, slots=True)
         
     | 
| 
       154 
     | 
    
         
            -
            class BaseInjectable[T](Injectable[T], ABC):
         
     | 
| 
       155 
     | 
    
         
            -
                factory: Callable[..., T]
         
     | 
| 
       156 
     | 
    
         
            -
             
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
       158 
     | 
    
         
            -
            class SimpleInjectable[T](BaseInjectable[T]):
         
     | 
| 
       159 
     | 
    
         
            -
                __slots__ = ()
         
     | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
       161 
     | 
    
         
            -
                @override
         
     | 
| 
       162 
     | 
    
         
            -
                def get_instance(self) -> T:
         
     | 
| 
       163 
     | 
    
         
            -
                    return self.factory()
         
     | 
| 
       164 
     | 
    
         
            -
             
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
            class SingletonInjectable[T](BaseInjectable[T]):
         
     | 
| 
       167 
     | 
    
         
            -
                __slots__ = ("__dict__",)
         
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
       169 
     | 
    
         
            -
                __key: ClassVar[str] = "$instance"
         
     | 
| 
       170 
     | 
    
         
            -
             
     | 
| 
       171 
     | 
    
         
            -
                @property
         
     | 
| 
       172 
     | 
    
         
            -
                def cache(self) -> MutableMapping[str, Any]:
         
     | 
| 
       173 
     | 
    
         
            -
                    return self.__dict__
         
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
                @property
         
     | 
| 
       176 
     | 
    
         
            -
                @override
         
     | 
| 
       177 
     | 
    
         
            -
                def is_locked(self) -> bool:
         
     | 
| 
       178 
     | 
    
         
            -
                    return self.__key in self.cache
         
     | 
| 
       179 
     | 
    
         
            -
             
     | 
| 
       180 
     | 
    
         
            -
                @override
         
     | 
| 
       181 
     | 
    
         
            -
                def unlock(self) -> None:
         
     | 
| 
       182 
     | 
    
         
            -
                    self.cache.clear()
         
     | 
| 
       183 
     | 
    
         
            -
             
     | 
| 
       184 
     | 
    
         
            -
                @override
         
     | 
| 
       185 
     | 
    
         
            -
                def get_instance(self) -> T:
         
     | 
| 
       186 
     | 
    
         
            -
                    with suppress(KeyError):
         
     | 
| 
       187 
     | 
    
         
            -
                        return self.cache[self.__key]
         
     | 
| 
       188 
     | 
    
         
            -
             
     | 
| 
       189 
     | 
    
         
            -
                    with synchronized():
         
     | 
| 
       190 
     | 
    
         
            -
                        instance = self.factory()
         
     | 
| 
       191 
     | 
    
         
            -
                        self.cache[self.__key] = instance
         
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
     | 
    
         
            -
                    return instance
         
     | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
       196 
     | 
    
         
            -
            @dataclass(repr=False, frozen=True, slots=True)
         
     | 
| 
       197 
     | 
    
         
            -
            class ShouldBeInjectable[T](Injectable[T]):
         
     | 
| 
       198 
     | 
    
         
            -
                cls: type[T]
         
     | 
| 
       199 
     | 
    
         
            -
             
     | 
| 
       200 
     | 
    
         
            -
                @override
         
     | 
| 
       201 
     | 
    
         
            -
                def get_instance(self) -> NoReturn:
         
     | 
| 
       202 
     | 
    
         
            -
                    raise InjectionError(f"`{self.cls}` should be an injectable.")
         
     | 
| 
       203 
     | 
    
         
            -
             
     | 
| 
       204 
     | 
    
         
            -
                @classmethod
         
     | 
| 
       205 
     | 
    
         
            -
                def from_callable(cls, callable: Callable[..., T]) -> Self:
         
     | 
| 
       206 
     | 
    
         
            -
                    if not isclass(callable):
         
     | 
| 
       207 
     | 
    
         
            -
                        raise TypeError(f"`{callable}` should be a class.")
         
     | 
| 
       208 
     | 
    
         
            -
             
     | 
| 
       209 
     | 
    
         
            -
                    return cls(callable)
         
     | 
| 
       210 
     | 
    
         
            -
             
     | 
| 
       211 
     | 
    
         
            -
             
     | 
| 
       212 
146 
     | 
    
         
             
            """
         
     | 
| 
       213 
147 
     | 
    
         
             
            Broker
         
     | 
| 
       214 
148 
     | 
    
         
             
            """
         
     | 
| 
         @@ -235,6 +169,10 @@ class Broker(Protocol): 
     | 
|
| 
       235 
169 
     | 
    
         
             
                def unlock(self) -> Self:
         
     | 
| 
       236 
170 
     | 
    
         
             
                    raise NotImplementedError
         
     | 
| 
       237 
171 
     | 
    
         | 
| 
      
 172 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
      
 173 
     | 
    
         
            +
                async def all_ready(self) -> None:
         
     | 
| 
      
 174 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
       238 
176 
     | 
    
         | 
| 
       239 
177 
     | 
    
         
             
            """
         
     | 
| 
       240 
178 
     | 
    
         
             
            Locator
         
     | 
| 
         @@ -257,7 +195,7 @@ class Mode(StrEnum): 
     | 
|
| 
       257 
195 
     | 
    
         | 
| 
       258 
196 
     | 
    
         
             
            type ModeStr = Literal["fallback", "normal", "override"]
         
     | 
| 
       259 
197 
     | 
    
         | 
| 
       260 
     | 
    
         
            -
            type InjectableFactory[T] = Callable[[ 
     | 
| 
      
 198 
     | 
    
         
            +
            type InjectableFactory[T] = Callable[[Caller[..., T]], Injectable[T]]
         
     | 
| 
       261 
199 
     | 
    
         | 
| 
       262 
200 
     | 
    
         | 
| 
       263 
201 
     | 
    
         
             
            class Record[T](NamedTuple):
         
     | 
| 
         @@ -267,7 +205,7 @@ class Record[T](NamedTuple): 
     | 
|
| 
       267 
205 
     | 
    
         | 
| 
       268 
206 
     | 
    
         
             
            @dataclass(repr=False, eq=False, kw_only=True, slots=True)
         
     | 
| 
       269 
207 
     | 
    
         
             
            class Updater[T]:
         
     | 
| 
       270 
     | 
    
         
            -
                factory:  
     | 
| 
      
 208 
     | 
    
         
            +
                factory: Caller[..., T]
         
     | 
| 
       271 
209 
     | 
    
         
             
                classes: Iterable[InputType[T]]
         
     | 
| 
       272 
210 
     | 
    
         
             
                injectable_factory: InjectableFactory[T]
         
     | 
| 
       273 
211 
     | 
    
         
             
                mode: Mode
         
     | 
| 
         @@ -354,6 +292,11 @@ class Locator(Broker): 
     | 
|
| 
       354 
292 
     | 
    
         | 
| 
       355 
293 
     | 
    
         
             
                    return self
         
     | 
| 
       356 
294 
     | 
    
         | 
| 
      
 295 
     | 
    
         
            +
                @override
         
     | 
| 
      
 296 
     | 
    
         
            +
                async def all_ready(self) -> None:
         
     | 
| 
      
 297 
     | 
    
         
            +
                    for injectable in self.__injectables:
         
     | 
| 
      
 298 
     | 
    
         
            +
                        await injectable.aget_instance()
         
     | 
| 
      
 299 
     | 
    
         
            +
             
     | 
| 
       357 
300 
     | 
    
         
             
                def add_listener(self, listener: EventListener) -> Self:
         
     | 
| 
       358 
301 
     | 
    
         
             
                    self.__channel.add_listener(listener)
         
     | 
| 
       359 
302 
     | 
    
         
             
                    return self
         
     | 
| 
         @@ -466,18 +409,20 @@ class Module(Broker, EventListener): 
     | 
|
| 
       466 
409 
     | 
    
         
             
                    yield from tuple(self.__modules)
         
     | 
| 
       467 
410 
     | 
    
         
             
                    yield self.__locator
         
     | 
| 
       468 
411 
     | 
    
         | 
| 
       469 
     | 
    
         
            -
                def injectable[**P, T]( 
     | 
| 
      
 412 
     | 
    
         
            +
                def injectable[**P, T](
         
     | 
| 
       470 
413 
     | 
    
         
             
                    self,
         
     | 
| 
       471 
     | 
    
         
            -
                    wrapped: Callable[P, T] | None = None,
         
     | 
| 
      
 414 
     | 
    
         
            +
                    wrapped: Callable[P, T] | Callable[P, Awaitable[T]] | None = None,
         
     | 
| 
       472 
415 
     | 
    
         
             
                    /,
         
     | 
| 
       473 
416 
     | 
    
         
             
                    *,
         
     | 
| 
       474 
417 
     | 
    
         
             
                    cls: InjectableFactory[T] = SimpleInjectable,
         
     | 
| 
       475 
418 
     | 
    
         
             
                    inject: bool = True,
         
     | 
| 
       476 
419 
     | 
    
         
             
                    on: TypeInfo[T] = (),
         
     | 
| 
       477 
420 
     | 
    
         
             
                    mode: Mode | ModeStr = Mode.get_default(),
         
     | 
| 
       478 
     | 
    
         
            -
                ):
         
     | 
| 
       479 
     | 
    
         
            -
                    def decorator( 
     | 
| 
       480 
     | 
    
         
            -
                         
     | 
| 
      
 421 
     | 
    
         
            +
                ) -> Any:
         
     | 
| 
      
 422 
     | 
    
         
            +
                    def decorator(
         
     | 
| 
      
 423 
     | 
    
         
            +
                        wp: Callable[P, T] | Callable[P, Awaitable[T]],
         
     | 
| 
      
 424 
     | 
    
         
            +
                    ) -> Callable[P, T] | Callable[P, Awaitable[T]]:
         
     | 
| 
      
 425 
     | 
    
         
            +
                        factory = _get_caller(self.make_injected_function(wp) if inject else wp)
         
     | 
| 
       481 
426 
     | 
    
         
             
                        classes = get_return_types(wp, on)
         
     | 
| 
       482 
427 
     | 
    
         
             
                        updater = Updater(
         
     | 
| 
       483 
428 
     | 
    
         
             
                            factory=factory,
         
     | 
| 
         @@ -492,12 +437,12 @@ class Module(Broker, EventListener): 
     | 
|
| 
       492 
437 
     | 
    
         | 
| 
       493 
438 
     | 
    
         
             
                singleton = partialmethod(injectable, cls=SingletonInjectable)
         
     | 
| 
       494 
439 
     | 
    
         | 
| 
       495 
     | 
    
         
            -
                def should_be_injectable[T](self, wrapped: type[T] | None = None, /) 
     | 
| 
       496 
     | 
    
         
            -
                    def decorator(wp 
     | 
| 
      
 440 
     | 
    
         
            +
                def should_be_injectable[T](self, wrapped: type[T] | None = None, /) -> Any:
         
     | 
| 
      
 441 
     | 
    
         
            +
                    def decorator(wp: type[T]) -> type[T]:
         
     | 
| 
       497 
442 
     | 
    
         
             
                        updater = Updater(
         
     | 
| 
       498 
     | 
    
         
            -
                            factory=wp,
         
     | 
| 
      
 443 
     | 
    
         
            +
                            factory=SyncCaller(wp),
         
     | 
| 
       499 
444 
     | 
    
         
             
                            classes=(wp,),
         
     | 
| 
       500 
     | 
    
         
            -
                            injectable_factory=ShouldBeInjectable 
     | 
| 
      
 445 
     | 
    
         
            +
                            injectable_factory=lambda _: ShouldBeInjectable(wp),
         
     | 
| 
       501 
446 
     | 
    
         
             
                            mode=Mode.FALLBACK,
         
     | 
| 
       502 
447 
     | 
    
         
             
                        )
         
     | 
| 
       503 
448 
     | 
    
         
             
                        self.update(updater)
         
     | 
| 
         @@ -505,15 +450,15 @@ class Module(Broker, EventListener): 
     | 
|
| 
       505 
450 
     | 
    
         | 
| 
       506 
451 
     | 
    
         
             
                    return decorator(wrapped) if wrapped else decorator
         
     | 
| 
       507 
452 
     | 
    
         | 
| 
       508 
     | 
    
         
            -
                def constant[T]( 
     | 
| 
      
 453 
     | 
    
         
            +
                def constant[T](
         
     | 
| 
       509 
454 
     | 
    
         
             
                    self,
         
     | 
| 
       510 
455 
     | 
    
         
             
                    wrapped: type[T] | None = None,
         
     | 
| 
       511 
456 
     | 
    
         
             
                    /,
         
     | 
| 
       512 
457 
     | 
    
         
             
                    *,
         
     | 
| 
       513 
458 
     | 
    
         
             
                    on: TypeInfo[T] = (),
         
     | 
| 
       514 
459 
     | 
    
         
             
                    mode: Mode | ModeStr = Mode.get_default(),
         
     | 
| 
       515 
     | 
    
         
            -
                ):
         
     | 
| 
       516 
     | 
    
         
            -
                    def decorator(wp 
     | 
| 
      
 460 
     | 
    
         
            +
                ) -> Any:
         
     | 
| 
      
 461 
     | 
    
         
            +
                    def decorator(wp: type[T]) -> type[T]:
         
     | 
| 
       517 
462 
     | 
    
         
             
                        lazy_instance = Lazy(wp)
         
     | 
| 
       518 
463 
     | 
    
         
             
                        self.injectable(
         
     | 
| 
       519 
464 
     | 
    
         
             
                            lambda: ~lazy_instance,
         
     | 
| 
         @@ -545,8 +490,8 @@ class Module(Broker, EventListener): 
     | 
|
| 
       545 
490 
     | 
    
         
             
                    )
         
     | 
| 
       546 
491 
     | 
    
         
             
                    return self
         
     | 
| 
       547 
492 
     | 
    
         | 
| 
       548 
     | 
    
         
            -
                def inject[**P, T](self, wrapped: Callable[P, T] | None = None, /) 
     | 
| 
       549 
     | 
    
         
            -
                    def decorator(wp 
     | 
| 
      
 493 
     | 
    
         
            +
                def inject[**P, T](self, wrapped: Callable[P, T] | None = None, /) -> Any:
         
     | 
| 
      
 494 
     | 
    
         
            +
                    def decorator(wp: Callable[P, T]) -> Callable[P, T]:
         
     | 
| 
       550 
495 
     | 
    
         
             
                        if isclass(wp):
         
     | 
| 
       551 
496 
     | 
    
         
             
                            wp.__init__ = self.inject(wp.__init__)
         
     | 
| 
       552 
497 
     | 
    
         
             
                            return wp
         
     | 
| 
         @@ -555,47 +500,135 @@ class Module(Broker, EventListener): 
     | 
|
| 
       555 
500 
     | 
    
         | 
| 
       556 
501 
     | 
    
         
             
                    return decorator(wrapped) if wrapped else decorator
         
     | 
| 
       557 
502 
     | 
    
         | 
| 
      
 503 
     | 
    
         
            +
                @overload
         
     | 
| 
       558 
504 
     | 
    
         
             
                def make_injected_function[**P, T](
         
     | 
| 
       559 
505 
     | 
    
         
             
                    self,
         
     | 
| 
       560 
506 
     | 
    
         
             
                    wrapped: Callable[P, T],
         
     | 
| 
       561 
507 
     | 
    
         
             
                    /,
         
     | 
| 
       562 
     | 
    
         
            -
                ) ->  
     | 
| 
       563 
     | 
    
         
            -
             
     | 
| 
      
 508 
     | 
    
         
            +
                ) -> SyncInjectedFunction[P, T]: ...
         
     | 
| 
      
 509 
     | 
    
         
            +
             
     | 
| 
      
 510 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 511 
     | 
    
         
            +
                def make_injected_function[**P, T](
         
     | 
| 
      
 512 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 513 
     | 
    
         
            +
                    wrapped: Callable[P, Awaitable[T]],
         
     | 
| 
      
 514 
     | 
    
         
            +
                    /,
         
     | 
| 
      
 515 
     | 
    
         
            +
                ) -> AsyncInjectedFunction[P, T]: ...
         
     | 
| 
      
 516 
     | 
    
         
            +
             
     | 
| 
      
 517 
     | 
    
         
            +
                def make_injected_function(self, wrapped, /):  # type: ignore[no-untyped-def]
         
     | 
| 
      
 518 
     | 
    
         
            +
                    metadata = InjectMetadata(wrapped)
         
     | 
| 
       564 
519 
     | 
    
         | 
| 
       565 
     | 
    
         
            -
                    @ 
     | 
| 
      
 520 
     | 
    
         
            +
                    @metadata.on_setup
         
     | 
| 
       566 
521 
     | 
    
         
             
                    def listen() -> None:
         
     | 
| 
       567 
     | 
    
         
            -
                         
     | 
| 
       568 
     | 
    
         
            -
                        self.add_listener( 
     | 
| 
      
 522 
     | 
    
         
            +
                        metadata.update(self)
         
     | 
| 
      
 523 
     | 
    
         
            +
                        self.add_listener(metadata)
         
     | 
| 
      
 524 
     | 
    
         
            +
             
     | 
| 
      
 525 
     | 
    
         
            +
                    if iscoroutinefunction(wrapped):
         
     | 
| 
      
 526 
     | 
    
         
            +
                        return AsyncInjectedFunction(metadata)
         
     | 
| 
       569 
527 
     | 
    
         | 
| 
       570 
     | 
    
         
            -
                    return  
     | 
| 
      
 528 
     | 
    
         
            +
                    return SyncInjectedFunction(metadata)
         
     | 
| 
      
 529 
     | 
    
         
            +
             
     | 
| 
      
 530 
     | 
    
         
            +
                async def afind_instance[T](self, cls: InputType[T]) -> T:
         
     | 
| 
      
 531 
     | 
    
         
            +
                    injectable = self[cls]
         
     | 
| 
      
 532 
     | 
    
         
            +
                    return await injectable.aget_instance()
         
     | 
| 
       571 
533 
     | 
    
         | 
| 
       572 
534 
     | 
    
         
             
                def find_instance[T](self, cls: InputType[T]) -> T:
         
     | 
| 
       573 
535 
     | 
    
         
             
                    injectable = self[cls]
         
     | 
| 
       574 
536 
     | 
    
         
             
                    return injectable.get_instance()
         
     | 
| 
       575 
537 
     | 
    
         | 
| 
      
 538 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 539 
     | 
    
         
            +
                async def aget_instance[T, Default](
         
     | 
| 
      
 540 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 541 
     | 
    
         
            +
                    cls: InputType[T],
         
     | 
| 
      
 542 
     | 
    
         
            +
                    default: Default,
         
     | 
| 
      
 543 
     | 
    
         
            +
                ) -> T | Default: ...
         
     | 
| 
      
 544 
     | 
    
         
            +
             
     | 
| 
      
 545 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 546 
     | 
    
         
            +
                async def aget_instance[T](
         
     | 
| 
      
 547 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 548 
     | 
    
         
            +
                    cls: InputType[T],
         
     | 
| 
      
 549 
     | 
    
         
            +
                    default: None = ...,
         
     | 
| 
      
 550 
     | 
    
         
            +
                ) -> T | None: ...
         
     | 
| 
      
 551 
     | 
    
         
            +
             
     | 
| 
      
 552 
     | 
    
         
            +
                async def aget_instance(self, cls, default=None):  # type: ignore[no-untyped-def]
         
     | 
| 
      
 553 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 554 
     | 
    
         
            +
                        return await self.afind_instance(cls)
         
     | 
| 
      
 555 
     | 
    
         
            +
                    except KeyError:
         
     | 
| 
      
 556 
     | 
    
         
            +
                        return default
         
     | 
| 
      
 557 
     | 
    
         
            +
             
     | 
| 
      
 558 
     | 
    
         
            +
                @overload
         
     | 
| 
       576 
559 
     | 
    
         
             
                def get_instance[T, Default](
         
     | 
| 
       577 
560 
     | 
    
         
             
                    self,
         
     | 
| 
       578 
561 
     | 
    
         
             
                    cls: InputType[T],
         
     | 
| 
       579 
     | 
    
         
            -
                    default: Default 
     | 
| 
       580 
     | 
    
         
            -
                ) -> T | Default  
     | 
| 
      
 562 
     | 
    
         
            +
                    default: Default,
         
     | 
| 
      
 563 
     | 
    
         
            +
                ) -> T | Default: ...
         
     | 
| 
      
 564 
     | 
    
         
            +
             
     | 
| 
      
 565 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 566 
     | 
    
         
            +
                def get_instance[T](
         
     | 
| 
      
 567 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 568 
     | 
    
         
            +
                    cls: InputType[T],
         
     | 
| 
      
 569 
     | 
    
         
            +
                    default: None = ...,
         
     | 
| 
      
 570 
     | 
    
         
            +
                ) -> T | None: ...
         
     | 
| 
      
 571 
     | 
    
         
            +
             
     | 
| 
      
 572 
     | 
    
         
            +
                def get_instance(self, cls, default=None):  # type: ignore[no-untyped-def]
         
     | 
| 
       581 
573 
     | 
    
         
             
                    try:
         
     | 
| 
       582 
574 
     | 
    
         
             
                        return self.find_instance(cls)
         
     | 
| 
       583 
575 
     | 
    
         
             
                    except KeyError:
         
     | 
| 
       584 
576 
     | 
    
         
             
                        return default
         
     | 
| 
       585 
577 
     | 
    
         | 
| 
      
 578 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 579 
     | 
    
         
            +
                def aget_lazy_instance[T, Default](
         
     | 
| 
      
 580 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 581 
     | 
    
         
            +
                    cls: InputType[T],
         
     | 
| 
      
 582 
     | 
    
         
            +
                    default: Default,
         
     | 
| 
      
 583 
     | 
    
         
            +
                    *,
         
     | 
| 
      
 584 
     | 
    
         
            +
                    cache: bool = ...,
         
     | 
| 
      
 585 
     | 
    
         
            +
                ) -> Awaitable[T | Default]: ...
         
     | 
| 
      
 586 
     | 
    
         
            +
             
     | 
| 
      
 587 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 588 
     | 
    
         
            +
                def aget_lazy_instance[T](
         
     | 
| 
      
 589 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 590 
     | 
    
         
            +
                    cls: InputType[T],
         
     | 
| 
      
 591 
     | 
    
         
            +
                    default: None = ...,
         
     | 
| 
      
 592 
     | 
    
         
            +
                    *,
         
     | 
| 
      
 593 
     | 
    
         
            +
                    cache: bool = ...,
         
     | 
| 
      
 594 
     | 
    
         
            +
                ) -> Awaitable[T | None]: ...
         
     | 
| 
      
 595 
     | 
    
         
            +
             
     | 
| 
      
 596 
     | 
    
         
            +
                def aget_lazy_instance(self, cls, default=None, *, cache=False):  # type: ignore[no-untyped-def]
         
     | 
| 
      
 597 
     | 
    
         
            +
                    if cache:
         
     | 
| 
      
 598 
     | 
    
         
            +
                        coroutine = self.aget_instance(cls, default)
         
     | 
| 
      
 599 
     | 
    
         
            +
                        return asyncio.ensure_future(coroutine)
         
     | 
| 
      
 600 
     | 
    
         
            +
             
     | 
| 
      
 601 
     | 
    
         
            +
                    function = self.make_injected_function(lambda instance=default: instance)
         
     | 
| 
      
 602 
     | 
    
         
            +
                    metadata = function.__inject_metadata__
         
     | 
| 
      
 603 
     | 
    
         
            +
                    metadata.set_owner(cls)
         
     | 
| 
      
 604 
     | 
    
         
            +
                    return SimpleAwaitable(metadata.acall)
         
     | 
| 
      
 605 
     | 
    
         
            +
             
     | 
| 
      
 606 
     | 
    
         
            +
                @overload
         
     | 
| 
       586 
607 
     | 
    
         
             
                def get_lazy_instance[T, Default](
         
     | 
| 
       587 
608 
     | 
    
         
             
                    self,
         
     | 
| 
       588 
609 
     | 
    
         
             
                    cls: InputType[T],
         
     | 
| 
       589 
     | 
    
         
            -
                    default: Default 
     | 
| 
      
 610 
     | 
    
         
            +
                    default: Default,
         
     | 
| 
       590 
611 
     | 
    
         
             
                    *,
         
     | 
| 
       591 
     | 
    
         
            -
                    cache: bool =  
     | 
| 
       592 
     | 
    
         
            -
                ) -> Invertible[T | Default 
     | 
| 
      
 612 
     | 
    
         
            +
                    cache: bool = ...,
         
     | 
| 
      
 613 
     | 
    
         
            +
                ) -> Invertible[T | Default]: ...
         
     | 
| 
      
 614 
     | 
    
         
            +
             
     | 
| 
      
 615 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 616 
     | 
    
         
            +
                def get_lazy_instance[T](
         
     | 
| 
      
 617 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 618 
     | 
    
         
            +
                    cls: InputType[T],
         
     | 
| 
      
 619 
     | 
    
         
            +
                    default: None = ...,
         
     | 
| 
      
 620 
     | 
    
         
            +
                    *,
         
     | 
| 
      
 621 
     | 
    
         
            +
                    cache: bool = ...,
         
     | 
| 
      
 622 
     | 
    
         
            +
                ) -> Invertible[T | None]: ...
         
     | 
| 
      
 623 
     | 
    
         
            +
             
     | 
| 
      
 624 
     | 
    
         
            +
                def get_lazy_instance(self, cls, default=None, *, cache=False):  # type: ignore[no-untyped-def]
         
     | 
| 
       593 
625 
     | 
    
         
             
                    if cache:
         
     | 
| 
       594 
626 
     | 
    
         
             
                        return Lazy(lambda: self.get_instance(cls, default))
         
     | 
| 
       595 
627 
     | 
    
         | 
| 
       596 
     | 
    
         
            -
                    function = self. 
     | 
| 
       597 
     | 
    
         
            -
                    function. 
     | 
| 
       598 
     | 
    
         
            -
                     
     | 
| 
      
 628 
     | 
    
         
            +
                    function = self.make_injected_function(lambda instance=default: instance)
         
     | 
| 
      
 629 
     | 
    
         
            +
                    metadata = function.__inject_metadata__
         
     | 
| 
      
 630 
     | 
    
         
            +
                    metadata.set_owner(cls)
         
     | 
| 
      
 631 
     | 
    
         
            +
                    return SimpleInvertible(metadata.call)
         
     | 
| 
       599 
632 
     | 
    
         | 
| 
       600 
633 
     | 
    
         
             
                def update[T](self, updater: Updater[T]) -> Self:
         
     | 
| 
       601 
634 
     | 
    
         
             
                    self.__locator.update(updater)
         
     | 
| 
         @@ -670,6 +703,11 @@ class Module(Broker, EventListener): 
     | 
|
| 
       670 
703 
     | 
    
         | 
| 
       671 
704 
     | 
    
         
             
                    return self
         
     | 
| 
       672 
705 
     | 
    
         | 
| 
      
 706 
     | 
    
         
            +
                @override
         
     | 
| 
      
 707 
     | 
    
         
            +
                async def all_ready(self) -> None:
         
     | 
| 
      
 708 
     | 
    
         
            +
                    for broker in self.__brokers:
         
     | 
| 
      
 709 
     | 
    
         
            +
                        await broker.all_ready()
         
     | 
| 
      
 710 
     | 
    
         
            +
             
     | 
| 
       673 
711 
     | 
    
         
             
                def add_logger(self, logger: Logger) -> Self:
         
     | 
| 
       674 
712 
     | 
    
         
             
                    self.__loggers.append(logger)
         
     | 
| 
       675 
713 
     | 
    
         
             
                    return self
         
     | 
| 
         @@ -730,6 +768,13 @@ class Module(Broker, EventListener): 
     | 
|
| 
       730 
768 
     | 
    
         
             
                    return cls.from_name("__default__")
         
     | 
| 
       731 
769 
     | 
    
         | 
| 
       732 
770 
     | 
    
         | 
| 
      
 771 
     | 
    
         
            +
            def mod(name: str | None = None, /) -> Module:
         
     | 
| 
      
 772 
     | 
    
         
            +
                if name is None:
         
     | 
| 
      
 773 
     | 
    
         
            +
                    return Module.default()
         
     | 
| 
      
 774 
     | 
    
         
            +
             
     | 
| 
      
 775 
     | 
    
         
            +
                return Module.from_name(name)
         
     | 
| 
      
 776 
     | 
    
         
            +
             
     | 
| 
      
 777 
     | 
    
         
            +
             
     | 
| 
       733 
778 
     | 
    
         
             
            """
         
     | 
| 
       734 
779 
     | 
    
         
             
            InjectedFunction
         
     | 
| 
       735 
780 
     | 
    
         
             
            """
         
     | 
| 
         @@ -744,7 +789,13 @@ class Dependencies: 
     | 
|
| 
       744 
789 
     | 
    
         | 
| 
       745 
790 
     | 
    
         
             
                def __iter__(self) -> Iterator[tuple[str, Any]]:
         
     | 
| 
       746 
791 
     | 
    
         
             
                    for name, injectable in self.mapping.items():
         
     | 
| 
       747 
     | 
    
         
            -
                         
     | 
| 
      
 792 
     | 
    
         
            +
                        instance = injectable.get_instance()
         
     | 
| 
      
 793 
     | 
    
         
            +
                        yield name, instance
         
     | 
| 
      
 794 
     | 
    
         
            +
             
     | 
| 
      
 795 
     | 
    
         
            +
                async def __aiter__(self) -> AsyncIterator[tuple[str, Any]]:
         
     | 
| 
      
 796 
     | 
    
         
            +
                    for name, injectable in self.mapping.items():
         
     | 
| 
      
 797 
     | 
    
         
            +
                        instance = await injectable.aget_instance()
         
     | 
| 
      
 798 
     | 
    
         
            +
                        yield name, instance
         
     | 
| 
       748 
799 
     | 
    
         | 
| 
       749 
800 
     | 
    
         
             
                @property
         
     | 
| 
       750 
801 
     | 
    
         
             
                def are_resolved(self) -> bool:
         
     | 
| 
         @@ -753,9 +804,11 @@ class Dependencies: 
     | 
|
| 
       753 
804 
     | 
    
         | 
| 
       754 
805 
     | 
    
         
             
                    return bool(self)
         
     | 
| 
       755 
806 
     | 
    
         | 
| 
       756 
     | 
    
         
            -
                 
     | 
| 
       757 
     | 
    
         
            -
             
     | 
| 
       758 
     | 
    
         
            -
             
     | 
| 
      
 807 
     | 
    
         
            +
                async def aget_arguments(self) -> dict[str, Any]:
         
     | 
| 
      
 808 
     | 
    
         
            +
                    return {key: value async for key, value in self}
         
     | 
| 
      
 809 
     | 
    
         
            +
             
     | 
| 
      
 810 
     | 
    
         
            +
                def get_arguments(self) -> dict[str, Any]:
         
     | 
| 
      
 811 
     | 
    
         
            +
                    return dict(self)
         
     | 
| 
       759 
812 
     | 
    
         | 
| 
       760 
813 
     | 
    
         
             
                @classmethod
         
     | 
| 
       761 
814 
     | 
    
         
             
                def from_mapping(cls, mapping: Mapping[str, Injectable[Any]]) -> Self:
         
     | 
| 
         @@ -810,7 +863,7 @@ class Arguments(NamedTuple): 
     | 
|
| 
       810 
863 
     | 
    
         
             
                kwargs: Mapping[str, Any]
         
     | 
| 
       811 
864 
     | 
    
         | 
| 
       812 
865 
     | 
    
         | 
| 
       813 
     | 
    
         
            -
            class  
     | 
| 
      
 866 
     | 
    
         
            +
            class InjectMetadata[**P, T](Caller[P, T], EventListener):
         
     | 
| 
       814 
867 
     | 
    
         
             
                __slots__ = (
         
     | 
| 
       815 
868 
     | 
    
         
             
                    "__dependencies",
         
     | 
| 
       816 
869 
     | 
    
         
             
                    "__owner",
         
     | 
| 
         @@ -831,11 +884,6 @@ class Injected[**P, T](EventListener): 
     | 
|
| 
       831 
884 
     | 
    
         
             
                    self.__setup_queue = Queue()
         
     | 
| 
       832 
885 
     | 
    
         
             
                    self.__wrapped = wrapped
         
     | 
| 
       833 
886 
     | 
    
         | 
| 
       834 
     | 
    
         
            -
                def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
       835 
     | 
    
         
            -
                    self.__setup()
         
     | 
| 
       836 
     | 
    
         
            -
                    arguments = self.bind(args, kwargs)
         
     | 
| 
       837 
     | 
    
         
            -
                    return self.wrapped(*arguments.args, **arguments.kwargs)
         
     | 
| 
       838 
     | 
    
         
            -
             
     | 
| 
       839 
887 
     | 
    
         
             
                @property
         
     | 
| 
       840 
888 
     | 
    
         
             
                def signature(self) -> Signature:
         
     | 
| 
       841 
889 
     | 
    
         
             
                    with suppress(AttributeError):
         
     | 
| 
         @@ -851,22 +899,33 @@ class Injected[**P, T](EventListener): 
     | 
|
| 
       851 
899 
     | 
    
         
             
                def wrapped(self) -> Callable[P, T]:
         
     | 
| 
       852 
900 
     | 
    
         
             
                    return self.__wrapped
         
     | 
| 
       853 
901 
     | 
    
         | 
| 
      
 902 
     | 
    
         
            +
                async def abind(
         
     | 
| 
      
 903 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 904 
     | 
    
         
            +
                    args: Iterable[Any] = (),
         
     | 
| 
      
 905 
     | 
    
         
            +
                    kwargs: Mapping[str, Any] | None = None,
         
     | 
| 
      
 906 
     | 
    
         
            +
                ) -> Arguments:
         
     | 
| 
      
 907 
     | 
    
         
            +
                    additional_arguments = await self.__dependencies.aget_arguments()
         
     | 
| 
      
 908 
     | 
    
         
            +
                    return self.__bind(args, kwargs, additional_arguments)
         
     | 
| 
      
 909 
     | 
    
         
            +
             
     | 
| 
       854 
910 
     | 
    
         
             
                def bind(
         
     | 
| 
       855 
911 
     | 
    
         
             
                    self,
         
     | 
| 
       856 
912 
     | 
    
         
             
                    args: Iterable[Any] = (),
         
     | 
| 
       857 
913 
     | 
    
         
             
                    kwargs: Mapping[str, Any] | None = None,
         
     | 
| 
       858 
914 
     | 
    
         
             
                ) -> Arguments:
         
     | 
| 
       859 
     | 
    
         
            -
                     
     | 
| 
       860 
     | 
    
         
            -
             
     | 
| 
      
 915 
     | 
    
         
            +
                    additional_arguments = self.__dependencies.get_arguments()
         
     | 
| 
      
 916 
     | 
    
         
            +
                    return self.__bind(args, kwargs, additional_arguments)
         
     | 
| 
       861 
917 
     | 
    
         | 
| 
       862 
     | 
    
         
            -
             
     | 
| 
       863 
     | 
    
         
            -
             
     | 
| 
      
 918 
     | 
    
         
            +
                @override
         
     | 
| 
      
 919 
     | 
    
         
            +
                async def acall(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
      
 920 
     | 
    
         
            +
                    self.__setup()
         
     | 
| 
      
 921 
     | 
    
         
            +
                    arguments = await self.abind(args, kwargs)
         
     | 
| 
      
 922 
     | 
    
         
            +
                    return self.wrapped(*arguments.args, **arguments.kwargs)
         
     | 
| 
       864 
923 
     | 
    
         | 
| 
       865 
     | 
    
         
            -
             
     | 
| 
       866 
     | 
    
         
            -
             
     | 
| 
       867 
     | 
    
         
            -
             
     | 
| 
       868 
     | 
    
         
            -
                    )
         
     | 
| 
       869 
     | 
    
         
            -
                    return  
     | 
| 
      
 924 
     | 
    
         
            +
                @override
         
     | 
| 
      
 925 
     | 
    
         
            +
                def call(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
      
 926 
     | 
    
         
            +
                    self.__setup()
         
     | 
| 
      
 927 
     | 
    
         
            +
                    arguments = self.bind(args, kwargs)
         
     | 
| 
      
 928 
     | 
    
         
            +
                    return self.wrapped(*arguments.args, **arguments.kwargs)
         
     | 
| 
       870 
929 
     | 
    
         | 
| 
       871 
930 
     | 
    
         
             
                def set_owner(self, owner: type) -> Self:
         
     | 
| 
       872 
931 
     | 
    
         
             
                    if self.__dependencies.are_resolved:
         
     | 
| 
         @@ -885,8 +944,8 @@ class Injected[**P, T](EventListener): 
     | 
|
| 
       885 
944 
     | 
    
         
             
                    self.__dependencies = Dependencies.resolve(self.signature, module, self.__owner)
         
     | 
| 
       886 
945 
     | 
    
         
             
                    return self
         
     | 
| 
       887 
946 
     | 
    
         | 
| 
       888 
     | 
    
         
            -
                def on_setup[**_P, _T](self, wrapped: Callable[_P, _T] | None = None, /) 
     | 
| 
       889 
     | 
    
         
            -
                    def decorator(wp 
     | 
| 
      
 947 
     | 
    
         
            +
                def on_setup[**_P, _T](self, wrapped: Callable[_P, _T] | None = None, /) -> Any:
         
     | 
| 
      
 948 
     | 
    
         
            +
                    def decorator(wp: Callable[_P, _T]) -> Callable[_P, _T]:
         
     | 
| 
       890 
949 
     | 
    
         
             
                        queue = self.__setup_queue
         
     | 
| 
       891 
950 
     | 
    
         | 
| 
       892 
951 
     | 
    
         
             
                        if queue is None:
         
     | 
| 
         @@ -908,6 +967,22 @@ class Injected[**P, T](EventListener): 
     | 
|
| 
       908 
967 
     | 
    
         
             
                    yield
         
     | 
| 
       909 
968 
     | 
    
         
             
                    self.update(event.module)
         
     | 
| 
       910 
969 
     | 
    
         | 
| 
      
 970 
     | 
    
         
            +
                def __bind(
         
     | 
| 
      
 971 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 972 
     | 
    
         
            +
                    args: Iterable[Any],
         
     | 
| 
      
 973 
     | 
    
         
            +
                    kwargs: Mapping[str, Any] | None,
         
     | 
| 
      
 974 
     | 
    
         
            +
                    additional_arguments: dict[str, Any] | None,
         
     | 
| 
      
 975 
     | 
    
         
            +
                ) -> Arguments:
         
     | 
| 
      
 976 
     | 
    
         
            +
                    if kwargs is None:
         
     | 
| 
      
 977 
     | 
    
         
            +
                        kwargs = {}
         
     | 
| 
      
 978 
     | 
    
         
            +
             
     | 
| 
      
 979 
     | 
    
         
            +
                    if not additional_arguments:
         
     | 
| 
      
 980 
     | 
    
         
            +
                        return Arguments(args, kwargs)
         
     | 
| 
      
 981 
     | 
    
         
            +
             
     | 
| 
      
 982 
     | 
    
         
            +
                    bound = self.signature.bind_partial(*args, **kwargs)
         
     | 
| 
      
 983 
     | 
    
         
            +
                    bound.arguments = bound.arguments | additional_arguments | bound.arguments
         
     | 
| 
      
 984 
     | 
    
         
            +
                    return Arguments(bound.args, bound.kwargs)
         
     | 
| 
      
 985 
     | 
    
         
            +
             
     | 
| 
       911 
986 
     | 
    
         
             
                def __close_setup_queue(self) -> None:
         
     | 
| 
       912 
987 
     | 
    
         
             
                    self.__setup_queue = None
         
     | 
| 
       913 
988 
     | 
    
         | 
| 
         @@ -930,25 +1005,26 @@ class Injected[**P, T](EventListener): 
     | 
|
| 
       930 
1005 
     | 
    
         
             
                    self.__close_setup_queue()
         
     | 
| 
       931 
1006 
     | 
    
         | 
| 
       932 
1007 
     | 
    
         | 
| 
       933 
     | 
    
         
            -
            class InjectedFunction[**P, T]:
         
     | 
| 
       934 
     | 
    
         
            -
                __slots__ = ("__dict__", " 
     | 
| 
      
 1008 
     | 
    
         
            +
            class InjectedFunction[**P, T](ABC):
         
     | 
| 
      
 1009 
     | 
    
         
            +
                __slots__ = ("__dict__", "__inject_metadata__")
         
     | 
| 
       935 
1010 
     | 
    
         | 
| 
       936 
     | 
    
         
            -
                 
     | 
| 
      
 1011 
     | 
    
         
            +
                __inject_metadata__: InjectMetadata[P, T]
         
     | 
| 
       937 
1012 
     | 
    
         | 
| 
       938 
     | 
    
         
            -
                def __init__(self,  
     | 
| 
       939 
     | 
    
         
            -
                    update_wrapper(self,  
     | 
| 
       940 
     | 
    
         
            -
                    self. 
     | 
| 
      
 1013 
     | 
    
         
            +
                def __init__(self, metadata: InjectMetadata[P, T]) -> None:
         
     | 
| 
      
 1014 
     | 
    
         
            +
                    update_wrapper(self, metadata.wrapped)
         
     | 
| 
      
 1015 
     | 
    
         
            +
                    self.__inject_metadata__ = metadata
         
     | 
| 
       941 
1016 
     | 
    
         | 
| 
       942 
1017 
     | 
    
         
             
                @override
         
     | 
| 
       943 
1018 
     | 
    
         
             
                def __repr__(self) -> str:  # pragma: no cover
         
     | 
| 
       944 
     | 
    
         
            -
                    return repr(self. 
     | 
| 
      
 1019 
     | 
    
         
            +
                    return repr(self.__inject_metadata__.wrapped)
         
     | 
| 
       945 
1020 
     | 
    
         | 
| 
       946 
1021 
     | 
    
         
             
                @override
         
     | 
| 
       947 
1022 
     | 
    
         
             
                def __str__(self) -> str:  # pragma: no cover
         
     | 
| 
       948 
     | 
    
         
            -
                    return str(self. 
     | 
| 
      
 1023 
     | 
    
         
            +
                    return str(self.__inject_metadata__.wrapped)
         
     | 
| 
       949 
1024 
     | 
    
         | 
| 
      
 1025 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
       950 
1026 
     | 
    
         
             
                def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
       951 
     | 
    
         
            -
                     
     | 
| 
      
 1027 
     | 
    
         
            +
                    raise NotImplementedError
         
     | 
| 
       952 
1028 
     | 
    
         | 
| 
       953 
1029 
     | 
    
         
             
                def __get__(
         
     | 
| 
       954 
1030 
     | 
    
         
             
                    self,
         
     | 
| 
         @@ -961,4 +1037,43 @@ class InjectedFunction[**P, T]: 
     | 
|
| 
       961 
1037 
     | 
    
         
             
                    return MethodType(self, instance)
         
     | 
| 
       962 
1038 
     | 
    
         | 
| 
       963 
1039 
     | 
    
         
             
                def __set_name__(self, owner: type, name: str) -> None:
         
     | 
| 
       964 
     | 
    
         
            -
                    self. 
     | 
| 
      
 1040 
     | 
    
         
            +
                    self.__inject_metadata__.set_owner(owner)
         
     | 
| 
      
 1041 
     | 
    
         
            +
             
     | 
| 
      
 1042 
     | 
    
         
            +
             
     | 
| 
      
 1043 
     | 
    
         
            +
            class AsyncInjectedFunction[**P, T](InjectedFunction[P, Awaitable[T]]):
         
     | 
| 
      
 1044 
     | 
    
         
            +
                __slots__ = ()
         
     | 
| 
      
 1045 
     | 
    
         
            +
             
     | 
| 
      
 1046 
     | 
    
         
            +
                @override
         
     | 
| 
      
 1047 
     | 
    
         
            +
                async def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
      
 1048 
     | 
    
         
            +
                    return await (await self.__inject_metadata__.acall(*args, **kwargs))
         
     | 
| 
      
 1049 
     | 
    
         
            +
             
     | 
| 
      
 1050 
     | 
    
         
            +
             
     | 
| 
      
 1051 
     | 
    
         
            +
            class SyncInjectedFunction[**P, T](InjectedFunction[P, T]):
         
     | 
| 
      
 1052 
     | 
    
         
            +
                __slots__ = ()
         
     | 
| 
      
 1053 
     | 
    
         
            +
             
     | 
| 
      
 1054 
     | 
    
         
            +
                @override
         
     | 
| 
      
 1055 
     | 
    
         
            +
                def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
         
     | 
| 
      
 1056 
     | 
    
         
            +
                    return self.__inject_metadata__.call(*args, **kwargs)
         
     | 
| 
      
 1057 
     | 
    
         
            +
             
     | 
| 
      
 1058 
     | 
    
         
            +
             
     | 
| 
      
 1059 
     | 
    
         
            +
            def _is_coroutine_function[**P, T](
         
     | 
| 
      
 1060 
     | 
    
         
            +
                function: Callable[P, T] | Callable[P, Awaitable[T]],
         
     | 
| 
      
 1061 
     | 
    
         
            +
            ) -> TypeGuard[Callable[P, Awaitable[T]]]:
         
     | 
| 
      
 1062 
     | 
    
         
            +
                if iscoroutinefunction(function):
         
     | 
| 
      
 1063 
     | 
    
         
            +
                    return True
         
     | 
| 
      
 1064 
     | 
    
         
            +
             
     | 
| 
      
 1065 
     | 
    
         
            +
                elif isclass(function):
         
     | 
| 
      
 1066 
     | 
    
         
            +
                    return False
         
     | 
| 
      
 1067 
     | 
    
         
            +
             
     | 
| 
      
 1068 
     | 
    
         
            +
                call = getattr(function, "__call__", None)
         
     | 
| 
      
 1069 
     | 
    
         
            +
                return iscoroutinefunction(call)
         
     | 
| 
      
 1070 
     | 
    
         
            +
             
     | 
| 
      
 1071 
     | 
    
         
            +
             
     | 
| 
      
 1072 
     | 
    
         
            +
            def _get_caller[**P, T](function: Callable[P, T]) -> Caller[P, T]:
         
     | 
| 
      
 1073 
     | 
    
         
            +
                if _is_coroutine_function(function):
         
     | 
| 
      
 1074 
     | 
    
         
            +
                    return AsyncCaller(function)
         
     | 
| 
      
 1075 
     | 
    
         
            +
             
     | 
| 
      
 1076 
     | 
    
         
            +
                elif isinstance(function, InjectedFunction):
         
     | 
| 
      
 1077 
     | 
    
         
            +
                    return function.__inject_metadata__
         
     | 
| 
      
 1078 
     | 
    
         
            +
             
     | 
| 
      
 1079 
     | 
    
         
            +
                return SyncCaller(function)
         
     | 
| 
         @@ -1,4 +1,4 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            from collections.abc import  
     | 
| 
      
 1 
     | 
    
         
            +
            from collections.abc import Awaitable
         
     | 
| 
       2 
2 
     | 
    
         
             
            from types import GenericAlias
         
     | 
| 
       3 
3 
     | 
    
         
             
            from typing import Any, TypeAliasType
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
         @@ -28,18 +28,29 @@ def Inject[T](  # noqa: N802 
     | 
|
| 
       28 
28 
     | 
    
         | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
            class InjectionDependency[T]:
         
     | 
| 
       31 
     | 
    
         
            -
                __slots__ = (" 
     | 
| 
      
 31 
     | 
    
         
            +
                __slots__ = ("__class", "__lazy_instance", "__module")
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
                __call__: Callable[[], T]
         
     | 
| 
       34 
33 
     | 
    
         
             
                __class: type[T] | TypeAliasType | GenericAlias
         
     | 
| 
      
 34 
     | 
    
         
            +
                __lazy_instance: Awaitable[T]
         
     | 
| 
       35 
35 
     | 
    
         
             
                __module: Module
         
     | 
| 
       36 
36 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
                def __init__( 
     | 
| 
       38 
     | 
    
         
            -
                     
     | 
| 
       39 
     | 
    
         
            -
                     
     | 
| 
      
 37 
     | 
    
         
            +
                def __init__(
         
     | 
| 
      
 38 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 39 
     | 
    
         
            +
                    cls: type[T] | TypeAliasType | GenericAlias,
         
     | 
| 
      
 40 
     | 
    
         
            +
                    module: Module,
         
     | 
| 
      
 41 
     | 
    
         
            +
                ) -> None:
         
     | 
| 
       40 
42 
     | 
    
         
             
                    self.__class = cls
         
     | 
| 
      
 43 
     | 
    
         
            +
                    self.__lazy_instance = module.aget_lazy_instance(cls, default=NotImplemented)
         
     | 
| 
       41 
44 
     | 
    
         
             
                    self.__module = module
         
     | 
| 
       42 
45 
     | 
    
         | 
| 
      
 46 
     | 
    
         
            +
                async def __call__(self) -> T:
         
     | 
| 
      
 47 
     | 
    
         
            +
                    instance = await self.__lazy_instance
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                    if instance is NotImplemented:
         
     | 
| 
      
 50 
     | 
    
         
            +
                        raise InjectionError(f"`{self.__class}` is an unknown dependency.")
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    return instance
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
       43 
54 
     | 
    
         
             
                def __eq__(self, other: Any) -> bool:
         
     | 
| 
       44 
55 
     | 
    
         
             
                    if isinstance(other, type(self)):
         
     | 
| 
       45 
56 
     | 
    
         
             
                        return self.__key == other.__key
         
     | 
| 
         @@ -52,9 +63,3 @@ class InjectionDependency[T]: 
     | 
|
| 
       52 
63 
     | 
    
         
             
                @property
         
     | 
| 
       53 
64 
     | 
    
         
             
                def __key(self) -> tuple[type[T] | TypeAliasType | GenericAlias, Module]:
         
     | 
| 
       54 
65 
     | 
    
         
             
                    return self.__class, self.__module
         
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
                def __ensure(self, instance: T) -> T:
         
     | 
| 
       57 
     | 
    
         
            -
                    if instance is NotImplemented:
         
     | 
| 
       58 
     | 
    
         
            -
                        raise InjectionError(f"`{self.__class}` is an unknown dependency.")
         
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
                    return instance
         
     | 
| 
         @@ -8,7 +8,7 @@ test_constant = _.constant 
     | 
|
| 
       8 
8 
     | 
    
         
             
            test_injectable = _.injectable
         
     | 
| 
       9 
9 
     | 
    
         
             
            test_singleton = _.singleton
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
            def load_test_profile(* 
     | 
| 
      
 11 
     | 
    
         
            +
            def load_test_profile(*names: str) -> ContextManager[None]:
         
     | 
| 
       12 
12 
     | 
    
         
             
                """
         
     | 
| 
       13 
13 
     | 
    
         
             
                Context manager or decorator for temporary use test module.
         
     | 
| 
       14 
14 
     | 
    
         
             
                """
         
     | 
| 
         @@ -1,11 +1,11 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            [ 
     | 
| 
      
 1 
     | 
    
         
            +
            [project]
         
     | 
| 
       2 
2 
     | 
    
         
             
            name = "python-injection"
         
     | 
| 
       3 
     | 
    
         
            -
            version = "0. 
     | 
| 
      
 3 
     | 
    
         
            +
            version = "0.12.0"
         
     | 
| 
       4 
4 
     | 
    
         
             
            description = "Fast and easy dependency injection framework."
         
     | 
| 
       5 
5 
     | 
    
         
             
            license = "MIT"
         
     | 
| 
       6 
     | 
    
         
            -
            authors = ["remimd"]
         
     | 
| 
       7 
6 
     | 
    
         
             
            readme = "README.md"
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
      
 7 
     | 
    
         
            +
            requires-python = ">=3.12, <4"
         
     | 
| 
      
 8 
     | 
    
         
            +
            authors = [{ name = "remimd" }]
         
     | 
| 
       9 
9 
     | 
    
         
             
            keywords = ["dependencies", "dependency", "inject", "injection"]
         
     | 
| 
       10 
10 
     | 
    
         
             
            classifiers = [
         
     | 
| 
       11 
11 
     | 
    
         
             
                "Development Status :: 4 - Beta",
         
     | 
| 
         @@ -21,17 +21,19 @@ classifiers = [ 
     | 
|
| 
       21 
21 
     | 
    
         
             
                "Natural Language :: English",
         
     | 
| 
       22 
22 
     | 
    
         
             
                "Typing :: Typed",
         
     | 
| 
       23 
23 
     | 
    
         
             
            ]
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 24 
     | 
    
         
            +
            dependencies = []
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
            [ 
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
      
 26 
     | 
    
         
            +
            [project.urls]
         
     | 
| 
      
 27 
     | 
    
         
            +
            repository = "https://github.com/100nm/python-injection"
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            [tool.poetry]
         
     | 
| 
      
 30 
     | 
    
         
            +
            packages = [{ include = "injection" }]
         
     | 
| 
       28 
31 
     | 
    
         | 
| 
       29 
32 
     | 
    
         
             
            [tool.poetry.group.dev.dependencies]
         
     | 
| 
       30 
33 
     | 
    
         
             
            mypy = "*"
         
     | 
| 
       31 
34 
     | 
    
         
             
            ruff = "*"
         
     | 
| 
       32 
35 
     | 
    
         | 
| 
       33 
36 
     | 
    
         
             
            [tool.poetry.group.test.dependencies]
         
     | 
| 
       34 
     | 
    
         
            -
            blacksheep = { version = "*", optional = true }
         
     | 
| 
       35 
37 
     | 
    
         
             
            fastapi = "*"
         
     | 
| 
       36 
38 
     | 
    
         
             
            httpx = "*"
         
     | 
| 
       37 
39 
     | 
    
         
             
            pydantic = "*"
         
     | 
| 
         @@ -70,7 +72,6 @@ exclude = [ 
     | 
|
| 
       70 
72 
     | 
    
         
             
                "tests/",
         
     | 
| 
       71 
73 
     | 
    
         
             
                "bench.py",
         
     | 
| 
       72 
74 
     | 
    
         
             
                "conftest.py",
         
     | 
| 
       73 
     | 
    
         
            -
                "injection/integrations/blacksheep.py",
         
     | 
| 
       74 
75 
     | 
    
         
             
            ]
         
     | 
| 
       75 
76 
     | 
    
         
             
            follow_imports = "silent"
         
     | 
| 
       76 
77 
     | 
    
         
             
            no_implicit_reexport = true
         
     | 
| 
         @@ -85,7 +86,7 @@ warn_required_dynamic_aliases = true 
     | 
|
| 
       85 
86 
     | 
    
         | 
| 
       86 
87 
     | 
    
         
             
            [tool.pytest.ini_options]
         
     | 
| 
       87 
88 
     | 
    
         
             
            python_files = "test_*.py"
         
     | 
| 
       88 
     | 
    
         
            -
            addopts = "--tb short --cov ./ --cov-report term-missing:skip-covered 
     | 
| 
      
 89 
     | 
    
         
            +
            addopts = "--tb short --cov ./ --cov-report term-missing:skip-covered"
         
     | 
| 
       89 
90 
     | 
    
         
             
            asyncio_default_fixture_loop_scope = "session"
         
     | 
| 
       90 
91 
     | 
    
         
             
            asyncio_mode = "auto"
         
     | 
| 
       91 
92 
     | 
    
         
             
            testpaths = "**/tests/"
         
     | 
| 
         @@ -1,34 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            from typing import Any, override
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            from injection import Module, mod
         
     | 
| 
       4 
     | 
    
         
            -
            from injection.integrations import _is_installed
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
            __all__ = ("InjectionServices",)
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
            if _is_installed("blacksheep", __name__):
         
     | 
| 
       9 
     | 
    
         
            -
                from rodi import ContainerProtocol
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
            class InjectionServices(ContainerProtocol):
         
     | 
| 
       13 
     | 
    
         
            -
                """
         
     | 
| 
       14 
     | 
    
         
            -
                BlackSheep dependency injection container implemented with `python-injection`.
         
     | 
| 
       15 
     | 
    
         
            -
                """
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
                __slots__ = ("__module",)
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
                __module: Module
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
                def __init__(self, module: Module | None = None) -> None:
         
     | 
| 
       22 
     | 
    
         
            -
                    self.__module = module or mod()
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
                @override
         
     | 
| 
       25 
     | 
    
         
            -
                def __contains__(self, item: Any) -> bool:
         
     | 
| 
       26 
     | 
    
         
            -
                    return item in self.__module
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
                @override
         
     | 
| 
       29 
     | 
    
         
            -
                def register(self, obj_type: type | Any, *args: Any, **kwargs: Any) -> None:
         
     | 
| 
       30 
     | 
    
         
            -
                    self.__module.injectable(obj_type)
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                @override
         
     | 
| 
       33 
     | 
    
         
            -
                def resolve[T](self, obj_type: type[T] | Any, *args: Any, **kwargs: Any) -> T:
         
     | 
| 
       34 
     | 
    
         
            -
                    return self.__module.find_instance(obj_type)
         
     | 
| 
         
            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
         
     |