python-injection 0.17.3.post0__py3-none-any.whl → 0.18.0__py3-none-any.whl

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.
@@ -0,0 +1,147 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from collections.abc import AsyncIterator, Awaitable, Callable, Coroutine, Iterator
5
+ from contextlib import asynccontextmanager, contextmanager
6
+ from dataclasses import dataclass, field
7
+ from functools import wraps
8
+ from types import MethodType
9
+ from types import ModuleType as PythonModule
10
+ from typing import Any, Self, final, overload
11
+
12
+ from injection import Module, mod
13
+ from injection.loaders import PythonModuleLoader
14
+
15
+ __all__ = ("AsyncEntrypoint", "Entrypoint", "autocall", "entrypointmaker")
16
+
17
+ type AsyncEntrypoint[**P, T] = Entrypoint[P, Coroutine[Any, Any, T]]
18
+ type EntrypointDecorator[**P, T1, T2] = Callable[[Callable[P, T1]], Callable[P, T2]]
19
+ type EntrypointSetupMethod[*Ts, **P, T1, T2] = Callable[
20
+ [Entrypoint[P, T1], *Ts],
21
+ Entrypoint[P, T2],
22
+ ]
23
+
24
+
25
+ def autocall[**P, T](wrapped: Callable[P, T] | None = None, /) -> Any:
26
+ def decorator(wp: Callable[P, T]) -> Callable[P, T]:
27
+ wp() # type: ignore[call-arg]
28
+ return wp
29
+
30
+ return decorator(wrapped) if wrapped else decorator
31
+
32
+
33
+ @overload
34
+ def entrypointmaker[*Ts, **P, T1, T2](
35
+ wrapped: EntrypointSetupMethod[*Ts, P, T1, T2],
36
+ /,
37
+ *,
38
+ module: Module | None = ...,
39
+ ) -> EntrypointDecorator[P, T1, T2]: ...
40
+
41
+
42
+ @overload
43
+ def entrypointmaker[*Ts, **P, T1, T2](
44
+ wrapped: None = ...,
45
+ /,
46
+ *,
47
+ module: Module | None = ...,
48
+ ) -> Callable[
49
+ [EntrypointSetupMethod[*Ts, P, T1, T2]],
50
+ EntrypointDecorator[P, T1, T2],
51
+ ]: ...
52
+
53
+
54
+ def entrypointmaker[*Ts, **P, T1, T2](
55
+ wrapped: EntrypointSetupMethod[*Ts, P, T1, T2] | None = None,
56
+ /,
57
+ *,
58
+ module: Module | None = None,
59
+ ) -> Any:
60
+ def decorator(
61
+ wp: EntrypointSetupMethod[*Ts, P, T1, T2],
62
+ ) -> EntrypointDecorator[P, T1, T2]:
63
+ return Entrypoint._make_decorator(wp, module)
64
+
65
+ return decorator(wrapped) if wrapped else decorator
66
+
67
+
68
+ @final
69
+ @dataclass(repr=False, eq=False, frozen=True, slots=True)
70
+ class Entrypoint[**P, T]:
71
+ function: Callable[P, T]
72
+ module: Module = field(default_factory=mod)
73
+
74
+ def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
75
+ return self.function(*args, **kwargs)
76
+
77
+ def async_to_sync[_T](
78
+ self: AsyncEntrypoint[P, _T],
79
+ run: Callable[[Coroutine[Any, Any, _T]], _T] = asyncio.run,
80
+ /,
81
+ ) -> Entrypoint[P, _T]:
82
+ function = self.function
83
+
84
+ @wraps(function)
85
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> _T:
86
+ return run(function(*args, **kwargs))
87
+
88
+ return self.__recreate(wrapper)
89
+
90
+ def decorate(
91
+ self,
92
+ decorator: Callable[[Callable[P, T]], Callable[P, T]],
93
+ /,
94
+ ) -> Self:
95
+ return self.__recreate(decorator(self.function))
96
+
97
+ def inject(self) -> Self:
98
+ return self.decorate(self.module.make_injected_function)
99
+
100
+ def load_modules(
101
+ self,
102
+ /,
103
+ loader: PythonModuleLoader,
104
+ *packages: PythonModule | str,
105
+ ) -> Self:
106
+ return self.setup(lambda: loader.load(*packages))
107
+
108
+ def setup(self, function: Callable[..., Any], /) -> Self:
109
+ @contextmanager
110
+ def decorator() -> Iterator[Any]:
111
+ yield function()
112
+
113
+ return self.decorate(decorator())
114
+
115
+ def async_setup[_T](
116
+ self: AsyncEntrypoint[P, _T],
117
+ function: Callable[..., Awaitable[Any]],
118
+ /,
119
+ ) -> AsyncEntrypoint[P, _T]:
120
+ @asynccontextmanager
121
+ async def decorator() -> AsyncIterator[Any]:
122
+ yield await function()
123
+
124
+ return self.decorate(decorator())
125
+
126
+ def __recreate[**_P, _T](
127
+ self: Entrypoint[Any, Any],
128
+ function: Callable[_P, _T],
129
+ /,
130
+ ) -> Entrypoint[_P, _T]:
131
+ return type(self)(function, self.module)
132
+
133
+ @classmethod
134
+ def _make_decorator[*Ts, _T](
135
+ cls,
136
+ setup_method: EntrypointSetupMethod[*Ts, P, T, _T],
137
+ /,
138
+ module: Module | None = None,
139
+ ) -> EntrypointDecorator[P, T, _T]:
140
+ module = module or mod()
141
+ setup_method = module.make_injected_function(setup_method)
142
+
143
+ def decorator(function: Callable[P, T]) -> Callable[P, _T]:
144
+ self = cls(function, module)
145
+ return MethodType(setup_method, self)().function
146
+
147
+ return decorator
injection/loaders.py CHANGED
@@ -57,7 +57,7 @@ class PythonModuleLoader:
57
57
 
58
58
  def load(self, *packages: PythonModule | str) -> Self:
59
59
  modules = itertools.chain.from_iterable(
60
- self.__iter_modules(package) for package in packages
60
+ self.__iter_modules_from(package) for package in packages
61
61
  )
62
62
  self.__modules.update(modules)
63
63
  return self
@@ -67,7 +67,7 @@ class PythonModuleLoader:
67
67
  module_name in modules for modules in (self.__modules, self._sys_modules)
68
68
  )
69
69
 
70
- def __iter_modules(
70
+ def __iter_modules_from(
71
71
  self,
72
72
  package: PythonModule | str,
73
73
  ) -> Iterator[tuple[str, PythonModule | None]]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-injection
3
- Version: 0.17.3.post0
3
+ Version: 0.18.0
4
4
  Summary: Fast and easy dependency injection framework.
5
5
  Project-URL: Repository, https://github.com/100nm/python-injection
6
6
  Author: remimd
@@ -87,6 +87,7 @@ if __name__ == "__main__":
87
87
  * [**Scoped dependencies**](https://github.com/100nm/python-injection/tree/prod/documentation/scoped-dependencies.md)
88
88
  * [**Testing**](https://github.com/100nm/python-injection/tree/prod/documentation/testing.md)
89
89
  * [**Advanced usage**](https://github.com/100nm/python-injection/tree/prod/documentation/advanced-usage.md)
90
- * [**Utils**](https://github.com/100nm/python-injection/tree/prod/documentation/utils.md)
90
+ * [**Loaders**](https://github.com/100nm/python-injection/tree/prod/documentation/loaders.md)
91
+ * [**Entrypoint**](https://github.com/100nm/python-injection/tree/prod/documentation/entrypoint.md)
91
92
  * [**Integrations**](https://github.com/100nm/python-injection/tree/prod/documentation/integrations.md)
92
93
  * [**Concrete example**](https://github.com/100nm/python-injection-example)
@@ -1,7 +1,8 @@
1
1
  injection/__init__.py,sha256=7ZRUlO5EEPWO7IlbYHD-8DOX-cg4Np4nYq5fpw-U56o,1259
2
2
  injection/__init__.pyi,sha256=O2W6ZWcwH58JnDmJNkJ6cdoaO0D2NE7PEVFgfJNTwB0,10717
3
+ injection/entrypoint.py,sha256=wt8UoI2IFwn5A-nQe4GEPc6ynhRR7JXDWJxsHR3TKkU,4219
3
4
  injection/exceptions.py,sha256=v57yMujiq6H_zwwn30A8UYEZX9R9k-bY8FnsdaimPM4,1025
4
- injection/loaders.py,sha256=bLIVA_3N3mTEQ3kGV4YzrWEnokHxUGqWYNKPggOOnpg,4065
5
+ injection/loaders.py,sha256=8tS3zVvmxKf5E1ZJBTBjZpHkXETxNCL1dq8rbh2vzy4,4075
5
6
  injection/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
7
  injection/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
8
  injection/_core/descriptors.py,sha256=jH0pyIlPurMmU4yXr-HKS_7BJ-9d0XUvEx4pQre3QeI,704
@@ -21,6 +22,6 @@ injection/ext/fastapi.py,sha256=layUUer5IWiZX6Mmx1_RCYDLNCtEHtpya5ZL6TTBOkY,968
21
22
  injection/ext/fastapi.pyi,sha256=8OZEUjHFB9n7QXv_dtXdDuXW-r2huQEFsJ03gJOOvwQ,125
22
23
  injection/testing/__init__.py,sha256=PsrvNxYvn11if8CJpEYxcTxniqMt2w_7fBaDkY9RA5o,898
23
24
  injection/testing/__init__.pyi,sha256=iOii0i9F5n7znltGeGQYI2KXC_if9SAogLh1h03yx-0,540
24
- python_injection-0.17.3.post0.dist-info/METADATA,sha256=n-1M59B6b0yrl_d5BYkCGaPUj2T29RtOkqJq3y-mVNs,3266
25
- python_injection-0.17.3.post0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
26
- python_injection-0.17.3.post0.dist-info/RECORD,,
25
+ python_injection-0.18.0.dist-info/METADATA,sha256=SjlrHdr6R0csAv6-JVnPQarPgxYFSm0M1E6vZjhRLQ4,3364
26
+ python_injection-0.18.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
+ python_injection-0.18.0.dist-info/RECORD,,