python-injection 0.10.6__tar.gz → 0.10.8__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.
Files changed (22) hide show
  1. {python_injection-0.10.6 → python_injection-0.10.8}/PKG-INFO +1 -1
  2. {python_injection-0.10.6 → python_injection-0.10.8}/injection/__init__.pyi +5 -0
  3. {python_injection-0.10.6 → python_injection-0.10.8}/injection/_core/module.py +59 -68
  4. {python_injection-0.10.6 → python_injection-0.10.8}/pyproject.toml +2 -2
  5. {python_injection-0.10.6 → python_injection-0.10.8}/README.md +0 -0
  6. {python_injection-0.10.6 → python_injection-0.10.8}/injection/__init__.py +0 -0
  7. {python_injection-0.10.6 → python_injection-0.10.8}/injection/_core/__init__.py +0 -0
  8. {python_injection-0.10.6 → python_injection-0.10.8}/injection/_core/common/__init__.py +0 -0
  9. {python_injection-0.10.6 → python_injection-0.10.8}/injection/_core/common/event.py +0 -0
  10. {python_injection-0.10.6 → python_injection-0.10.8}/injection/_core/common/invertible.py +0 -0
  11. {python_injection-0.10.6 → python_injection-0.10.8}/injection/_core/common/lazy.py +0 -0
  12. {python_injection-0.10.6 → python_injection-0.10.8}/injection/_core/common/threading.py +0 -0
  13. {python_injection-0.10.6 → python_injection-0.10.8}/injection/_core/common/type.py +0 -0
  14. {python_injection-0.10.6 → python_injection-0.10.8}/injection/_core/hook.py +0 -0
  15. {python_injection-0.10.6 → python_injection-0.10.8}/injection/exceptions.py +0 -0
  16. {python_injection-0.10.6 → python_injection-0.10.8}/injection/integrations/__init__.py +0 -0
  17. {python_injection-0.10.6 → python_injection-0.10.8}/injection/integrations/blacksheep.py +0 -0
  18. {python_injection-0.10.6 → python_injection-0.10.8}/injection/integrations/fastapi.py +0 -0
  19. {python_injection-0.10.6 → python_injection-0.10.8}/injection/py.typed +0 -0
  20. {python_injection-0.10.6 → python_injection-0.10.8}/injection/testing/__init__.py +0 -0
  21. {python_injection-0.10.6 → python_injection-0.10.8}/injection/testing/__init__.pyi +0 -0
  22. {python_injection-0.10.6 → python_injection-0.10.8}/injection/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-injection
3
- Version: 0.10.6
3
+ Version: 0.10.8
4
4
  Summary: Fast and easy dependency injection framework.
5
5
  Home-page: https://github.com/100nm/python-injection
6
6
  License: MIT
@@ -125,6 +125,11 @@ class Module:
125
125
  that no dependencies are resolved, so the module doesn't need to be locked.
126
126
  """
127
127
 
128
+ def make_injected_function[**P, T](
129
+ self,
130
+ wrapped: Callable[P, T],
131
+ /,
132
+ ) -> Callable[P, T]: ...
128
133
  def find_instance[T](self, cls: _InputType[T]) -> T:
129
134
  """
130
135
  Function used to retrieve an instance associated with the type passed in
@@ -477,7 +477,7 @@ class Module(Broker, EventListener):
477
477
  mode: Mode | ModeStr = Mode.get_default(),
478
478
  ):
479
479
  def decorator(wp): # type: ignore[no-untyped-def]
480
- factory = self.inject(wp, return_factory=True) if inject else wp
480
+ factory = self.make_injected_function(wp) if inject else wp
481
481
  classes = get_return_types(wp, on)
482
482
  updater = Updater(
483
483
  factory=factory,
@@ -544,28 +544,29 @@ class Module(Broker, EventListener):
544
544
  )
545
545
  return self
546
546
 
547
- def inject[**P, T]( # type: ignore[no-untyped-def]
548
- self,
549
- wrapped: Callable[P, T] | None = None,
550
- /,
551
- *,
552
- return_factory: bool = False,
553
- ):
547
+ def inject[**P, T](self, wrapped: Callable[P, T] | None = None, /): # type: ignore[no-untyped-def]
554
548
  def decorator(wp): # type: ignore[no-untyped-def]
555
- if not return_factory and isclass(wp):
549
+ if isclass(wp):
556
550
  wp.__init__ = self.inject(wp.__init__)
557
551
  return wp
558
552
 
559
- function = InjectedFunction(wp)
553
+ return self.make_injected_function(wp)
554
+
555
+ return decorator(wrapped) if wrapped else decorator
560
556
 
561
- @function.on_setup
562
- def listen() -> None:
563
- function.update(self)
564
- self.add_listener(function)
557
+ def make_injected_function[**P, T](
558
+ self,
559
+ wrapped: Callable[P, T],
560
+ /,
561
+ ) -> InjectedFunction[P, T]:
562
+ injected = Injected(wrapped)
565
563
 
566
- return function
564
+ @injected.on_setup
565
+ def listen() -> None:
566
+ injected.update(self)
567
+ self.add_listener(injected)
567
568
 
568
- return decorator(wrapped) if wrapped else decorator
569
+ return InjectedFunction(injected)
569
570
 
570
571
  def find_instance[T](self, cls: InputType[T]) -> T:
571
572
  injectable = self[cls]
@@ -587,7 +588,7 @@ class Module(Broker, EventListener):
587
588
  return Lazy(lambda: self.get_instance(cls))
588
589
 
589
590
  function = self.inject(lambda instance=None: instance)
590
- function.set_owner(cls)
591
+ function.__injected__.set_owner(cls)
591
592
  return SimpleInvertible(function)
592
593
 
593
594
  def update[T](self, updater: Updater[T]) -> Self:
@@ -803,68 +804,46 @@ class Arguments(NamedTuple):
803
804
  kwargs: Mapping[str, Any]
804
805
 
805
806
 
806
- class InjectedFunction[**P, T](EventListener):
807
+ class Injected[**P, T](EventListener):
807
808
  __slots__ = (
808
- "__dict__",
809
- "__wrapped__",
810
809
  "__dependencies",
811
810
  "__owner",
812
811
  "__setup_queue",
812
+ "__signature",
813
+ "__wrapped",
813
814
  )
814
815
 
815
- __signature__: Signature
816
- __wrapped__: Callable[P, T]
817
816
  __dependencies: Dependencies
818
817
  __owner: type | None
819
818
  __setup_queue: Queue[Callable[..., Any]] | None
819
+ __signature: Signature
820
+ __wrapped: Callable[P, T]
820
821
 
821
822
  def __init__(self, wrapped: Callable[P, T], /) -> None:
822
- update_wrapper(self, wrapped, updated=())
823
- self.__update_vars_from(wrapped)
824
823
  self.__dependencies = Dependencies.empty()
825
824
  self.__owner = None
826
825
  self.__setup_queue = Queue()
827
-
828
- @override
829
- def __repr__(self) -> str: # pragma: no cover
830
- return repr(self.wrapped)
831
-
832
- @override
833
- def __str__(self) -> str: # pragma: no cover
834
- return str(self.wrapped)
826
+ self.__wrapped = wrapped
835
827
 
836
828
  def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
837
829
  self.__setup()
838
830
  arguments = self.bind(args, kwargs)
839
831
  return self.wrapped(*arguments.args, **arguments.kwargs)
840
832
 
841
- def __get__(
842
- self,
843
- instance: object | None = None,
844
- owner: type | None = None,
845
- ) -> Self | MethodType:
846
- if instance is None:
847
- return self
848
-
849
- return MethodType(self, instance)
850
-
851
- def __set_name__(self, owner: type, name: str) -> None:
852
- self.set_owner(owner)
853
-
854
833
  @property
855
834
  def signature(self) -> Signature:
856
835
  with suppress(AttributeError):
857
- return self.__signature__
836
+ return self.__signature
858
837
 
859
838
  with synchronized():
860
839
  signature = inspect.signature(self.wrapped, eval_str=True)
861
- self.__signature__ = signature
840
+ self.__signature = signature
862
841
 
863
842
  return signature
864
843
 
865
844
  @property
866
845
  def wrapped(self) -> Callable[P, T]:
867
- return self.__wrapped__
846
+ return self.__wrapped
868
847
 
869
848
  def bind(
870
849
  self,
@@ -944,24 +923,36 @@ class InjectedFunction[**P, T](EventListener):
944
923
  queue.join()
945
924
  self.__close_setup_queue()
946
925
 
947
- def __update_vars_from(self, obj: Any) -> None:
948
- try:
949
- variables = vars(obj)
950
- except TypeError:
951
- ...
952
- else:
953
- self.__update_vars(variables)
954
-
955
- def __update_vars(self, variables: Mapping[str, Any]) -> None:
956
- restricted_vars = frozenset(("__signature__", "__wrapped__")) | frozenset(
957
- var for var in dir(self) if not self.__is_dunder(var)
958
- )
959
- vars(self).update(
960
- (var, value)
961
- for var, value in variables.items()
962
- if var not in restricted_vars
963
- )
964
926
 
965
- @staticmethod
966
- def __is_dunder(var: str) -> bool:
967
- return var.startswith("__") and var.endswith("__")
927
+ class InjectedFunction[**P, T]:
928
+ __slots__ = ("__dict__", "__injected__")
929
+
930
+ __injected__: Injected[P, T]
931
+
932
+ def __init__(self, injected: Injected[P, T]) -> None:
933
+ update_wrapper(self, injected.wrapped)
934
+ self.__injected__ = injected
935
+
936
+ @override
937
+ def __repr__(self) -> str: # pragma: no cover
938
+ return repr(self.__injected__.wrapped)
939
+
940
+ @override
941
+ def __str__(self) -> str: # pragma: no cover
942
+ return str(self.__injected__.wrapped)
943
+
944
+ def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
945
+ return self.__injected__(*args, **kwargs)
946
+
947
+ def __get__(
948
+ self,
949
+ instance: object | None = None,
950
+ owner: type | None = None,
951
+ ) -> Self | MethodType:
952
+ if instance is None:
953
+ return self
954
+
955
+ return MethodType(self, instance)
956
+
957
+ def __set_name__(self, owner: type, name: str) -> None:
958
+ self.__injected__.set_owner(owner)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-injection"
3
- version = "0.10.6"
3
+ version = "0.10.8"
4
4
  description = "Fast and easy dependency injection framework."
5
5
  license = "MIT"
6
6
  authors = ["remimd"]
@@ -84,7 +84,7 @@ warn_required_dynamic_aliases = true
84
84
 
85
85
  [tool.pytest.ini_options]
86
86
  python_files = "test_*.py"
87
- addopts = "-p no:warnings --tb=short --cov=./ --cov-report term-missing:skip-covered"
87
+ addopts = "--tb short --cov ./ --cov-report term-missing:skip-covered"
88
88
  asyncio_default_fixture_loop_scope = "session"
89
89
  asyncio_mode = "auto"
90
90
  testpaths = "**/tests/"