python-injection 0.9.1__tar.gz → 0.9.3__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.
Potentially problematic release.
This version of python-injection might be problematic. Click here for more details.
- {python_injection-0.9.1 → python_injection-0.9.3}/PKG-INFO +1 -1
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/__init__.pyi +2 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/common/invertible.py +1 -1
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/common/lazy.py +2 -2
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/core/module.py +42 -23
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/testing/__init__.py +2 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/utils.py +12 -3
- {python_injection-0.9.1 → python_injection-0.9.3}/pyproject.toml +1 -1
- {python_injection-0.9.1 → python_injection-0.9.3}/documentation/basic-usage.md +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/__init__.py +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/common/__init__.py +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/common/event.py +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/common/tools/__init__.py +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/common/tools/threading.py +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/common/tools/type.py +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/core/__init__.py +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/exceptions.py +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/integrations/__init__.py +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/integrations/blacksheep.py +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/py.typed +0 -0
- {python_injection-0.9.1 → python_injection-0.9.3}/injection/testing/__init__.pyi +0 -0
|
@@ -2,6 +2,7 @@ from abc import abstractmethod
|
|
|
2
2
|
from collections.abc import Callable
|
|
3
3
|
from contextlib import ContextDecorator
|
|
4
4
|
from enum import StrEnum
|
|
5
|
+
from logging import Logger
|
|
5
6
|
from types import UnionType
|
|
6
7
|
from typing import (
|
|
7
8
|
Any,
|
|
@@ -179,6 +180,7 @@ class Module:
|
|
|
179
180
|
Function to unlock the module by deleting cached instances of singletons.
|
|
180
181
|
"""
|
|
181
182
|
|
|
183
|
+
def add_logger(self, logger: Logger) -> Self: ...
|
|
182
184
|
@classmethod
|
|
183
185
|
def from_name(cls, name: str) -> Self:
|
|
184
186
|
"""
|
|
@@ -9,7 +9,7 @@ __all__ = ("Lazy", "LazyMapping")
|
|
|
9
9
|
class Lazy[T](Invertible[T]):
|
|
10
10
|
__slots__ = ("__cache", "__is_set")
|
|
11
11
|
|
|
12
|
-
def __init__(self, factory: Callable[
|
|
12
|
+
def __init__(self, factory: Callable[..., T]):
|
|
13
13
|
self.__setup_cache(factory)
|
|
14
14
|
|
|
15
15
|
def __invert__(self) -> T:
|
|
@@ -19,7 +19,7 @@ class Lazy[T](Invertible[T]):
|
|
|
19
19
|
def is_set(self) -> bool:
|
|
20
20
|
return self.__is_set
|
|
21
21
|
|
|
22
|
-
def __setup_cache(self, factory: Callable[
|
|
22
|
+
def __setup_cache(self, factory: Callable[..., T]):
|
|
23
23
|
def cache_generator() -> Iterator[T]:
|
|
24
24
|
nonlocal factory
|
|
25
25
|
cached = factory()
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import inspect
|
|
4
|
-
import logging
|
|
5
4
|
from abc import ABC, abstractmethod
|
|
6
5
|
from collections import OrderedDict
|
|
7
6
|
from collections.abc import (
|
|
@@ -17,7 +16,8 @@ from dataclasses import dataclass, field
|
|
|
17
16
|
from enum import StrEnum
|
|
18
17
|
from functools import partialmethod, singledispatchmethod, update_wrapper
|
|
19
18
|
from inspect import Signature, isclass
|
|
20
|
-
from
|
|
19
|
+
from logging import Logger, getLogger
|
|
20
|
+
from queue import Empty, Queue
|
|
21
21
|
from types import MethodType, UnionType
|
|
22
22
|
from typing import (
|
|
23
23
|
Any,
|
|
@@ -59,8 +59,6 @@ __all__ = (
|
|
|
59
59
|
"PriorityStr",
|
|
60
60
|
)
|
|
61
61
|
|
|
62
|
-
_logger = logging.getLogger(__name__)
|
|
63
|
-
|
|
64
62
|
"""
|
|
65
63
|
Events
|
|
66
64
|
"""
|
|
@@ -161,7 +159,7 @@ class Injectable[T](Protocol):
|
|
|
161
159
|
|
|
162
160
|
@dataclass(repr=False, frozen=True, slots=True)
|
|
163
161
|
class BaseInjectable[T](Injectable[T], ABC):
|
|
164
|
-
factory: Callable[
|
|
162
|
+
factory: Callable[..., T]
|
|
165
163
|
|
|
166
164
|
|
|
167
165
|
class NewInjectable[T](BaseInjectable[T]):
|
|
@@ -386,6 +384,11 @@ class Module(EventListener, Broker):
|
|
|
386
384
|
init=False,
|
|
387
385
|
repr=False,
|
|
388
386
|
)
|
|
387
|
+
__loggers: list[Logger] = field(
|
|
388
|
+
default_factory=lambda: [getLogger(__name__)],
|
|
389
|
+
init=False,
|
|
390
|
+
repr=False,
|
|
391
|
+
)
|
|
389
392
|
|
|
390
393
|
__instances: ClassVar[dict[str, Module]] = {}
|
|
391
394
|
|
|
@@ -476,7 +479,7 @@ class Module(EventListener, Broker):
|
|
|
476
479
|
|
|
477
480
|
function = InjectedFunction(wp)
|
|
478
481
|
|
|
479
|
-
@function.on_setup
|
|
482
|
+
@function.on_setup
|
|
480
483
|
def listen():
|
|
481
484
|
function.update(self)
|
|
482
485
|
self.add_listener(function)
|
|
@@ -585,6 +588,10 @@ class Module(EventListener, Broker):
|
|
|
585
588
|
|
|
586
589
|
return self
|
|
587
590
|
|
|
591
|
+
def add_logger(self, logger: Logger) -> Self:
|
|
592
|
+
self.__loggers.append(logger)
|
|
593
|
+
return self
|
|
594
|
+
|
|
588
595
|
def add_listener(self, listener: EventListener) -> Self:
|
|
589
596
|
self.__channel.add_listener(listener)
|
|
590
597
|
return self
|
|
@@ -603,7 +610,7 @@ class Module(EventListener, Broker):
|
|
|
603
610
|
|
|
604
611
|
with self.__channel.dispatch(event):
|
|
605
612
|
yield
|
|
606
|
-
|
|
613
|
+
self.__send_debug(event)
|
|
607
614
|
|
|
608
615
|
def __check_locking(self):
|
|
609
616
|
if self.is_locked:
|
|
@@ -619,13 +626,19 @@ class Module(EventListener, Broker):
|
|
|
619
626
|
f"`{module}` can't be found in the modules used by `{self}`."
|
|
620
627
|
) from exc
|
|
621
628
|
|
|
629
|
+
def __send_debug(self, message: object):
|
|
630
|
+
for logger in self.__loggers:
|
|
631
|
+
logger.debug(message)
|
|
632
|
+
|
|
622
633
|
@classmethod
|
|
623
634
|
def from_name(cls, name: str) -> Self:
|
|
624
635
|
with suppress(KeyError):
|
|
625
636
|
return cls.__instances[name]
|
|
626
637
|
|
|
627
|
-
|
|
628
|
-
|
|
638
|
+
with synchronized():
|
|
639
|
+
instance = cls(name)
|
|
640
|
+
cls.__instances[name] = instance
|
|
641
|
+
|
|
629
642
|
return instance
|
|
630
643
|
|
|
631
644
|
@classmethod
|
|
@@ -723,10 +736,8 @@ class InjectedFunction(EventListener):
|
|
|
723
736
|
update_wrapper(self, wrapped, updated=())
|
|
724
737
|
self.__dependencies = Dependencies.empty()
|
|
725
738
|
self.__owner = None
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
queue.put_nowait(self.__set_signature)
|
|
729
|
-
self.__setup_queue = queue
|
|
739
|
+
self.__setup_queue = Queue[Callable[..., Any]](maxsize=2)
|
|
740
|
+
self.on_setup(self.__set_signature)
|
|
730
741
|
|
|
731
742
|
def __repr__(self) -> str: # pragma: no cover
|
|
732
743
|
return repr(self.wrapped)
|
|
@@ -735,13 +746,7 @@ class InjectedFunction(EventListener):
|
|
|
735
746
|
return str(self.wrapped)
|
|
736
747
|
|
|
737
748
|
def __call__(self, /, *args, **kwargs) -> Any:
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
while not queue.empty():
|
|
741
|
-
setup = queue.get()
|
|
742
|
-
setup()
|
|
743
|
-
queue.task_done()
|
|
744
|
-
|
|
749
|
+
self.__setup()
|
|
745
750
|
arguments = self.bind(args, kwargs)
|
|
746
751
|
return self.wrapped(*arguments.args, **arguments.kwargs)
|
|
747
752
|
|
|
@@ -796,15 +801,15 @@ class InjectedFunction(EventListener):
|
|
|
796
801
|
self.__dependencies = Dependencies.resolve(self.signature, module, self.__owner)
|
|
797
802
|
return self
|
|
798
803
|
|
|
799
|
-
def on_setup(self, wrapped: Callable[
|
|
804
|
+
def on_setup(self, wrapped: Callable[..., Any] = None, /):
|
|
800
805
|
def decorator(wp):
|
|
801
|
-
self.__setup_queue.
|
|
806
|
+
self.__setup_queue.put_nowait(wp)
|
|
802
807
|
return wp
|
|
803
808
|
|
|
804
809
|
return decorator(wrapped) if wrapped else decorator
|
|
805
810
|
|
|
806
811
|
@singledispatchmethod
|
|
807
|
-
def on_event(self, event: Event, /) -> None: # type: ignore
|
|
812
|
+
def on_event(self, event: Event, /) -> ContextManager | None: # type: ignore
|
|
808
813
|
return None
|
|
809
814
|
|
|
810
815
|
@on_event.register
|
|
@@ -813,6 +818,20 @@ class InjectedFunction(EventListener):
|
|
|
813
818
|
yield
|
|
814
819
|
self.update(event.on_module)
|
|
815
820
|
|
|
821
|
+
def __setup(self):
|
|
822
|
+
queue = self.__setup_queue
|
|
823
|
+
|
|
824
|
+
while True:
|
|
825
|
+
try:
|
|
826
|
+
task = queue.get_nowait()
|
|
827
|
+
except Empty:
|
|
828
|
+
break
|
|
829
|
+
|
|
830
|
+
task()
|
|
831
|
+
queue.task_done()
|
|
832
|
+
|
|
833
|
+
queue.join()
|
|
834
|
+
|
|
816
835
|
def __set_signature(self) -> Self:
|
|
817
836
|
self.__signature__ = inspect.signature(self.wrapped, eval_str=True)
|
|
818
837
|
return self
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
1
2
|
from importlib import import_module
|
|
2
3
|
from pkgutil import walk_packages
|
|
3
4
|
from types import ModuleType
|
|
@@ -5,9 +6,10 @@ from types import ModuleType
|
|
|
5
6
|
__all__ = ("load_package",)
|
|
6
7
|
|
|
7
8
|
|
|
8
|
-
def load_package(package: ModuleType | str):
|
|
9
|
+
def load_package(package: ModuleType | str, predicate: Callable[[str], bool] = None):
|
|
9
10
|
"""
|
|
10
11
|
Function for importing all modules in a Python package.
|
|
12
|
+
Pass the `predicate` parameter if you want to filter the modules to be imported.
|
|
11
13
|
"""
|
|
12
14
|
|
|
13
15
|
if isinstance(package, str):
|
|
@@ -20,8 +22,15 @@ def load_package(package: ModuleType | str):
|
|
|
20
22
|
"Package has no `__path__` attribute, as it's probably a module."
|
|
21
23
|
) from exc
|
|
22
24
|
|
|
25
|
+
if predicate is None:
|
|
26
|
+
|
|
27
|
+
def predicate(_: str) -> bool:
|
|
28
|
+
return True
|
|
29
|
+
|
|
23
30
|
for info in walk_packages(path=path, prefix=f"{package.__name__}."):
|
|
24
|
-
|
|
31
|
+
name = info.name
|
|
32
|
+
|
|
33
|
+
if info.ispkg or not predicate(name):
|
|
25
34
|
continue
|
|
26
35
|
|
|
27
|
-
import_module(
|
|
36
|
+
import_module(name)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|