Skip to content

Commit bce9bb1

Browse files
authored
feat: ✨ Improve decorator type hints
1 parent 0a4f63e commit bce9bb1

4 files changed

Lines changed: 230 additions & 82 deletions

File tree

injection/__init__.pyi

Lines changed: 148 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ from ._core.common.type import InputType as _InputType
1111
from ._core.common.type import TypeInfo as _TypeInfo
1212
from ._core.module import InjectableFactory as _InjectableFactory
1313
from ._core.module import ModeStr, PriorityStr
14-
from ._core.module import Recipe as _Recipe
1514
from ._core.scope import ScopeKindStr
1615

16+
type _Decorator[T] = Callable[[T], T]
17+
1718
__MODULE: Final[Module] = ...
1819

1920
afind_instance = __MODULE.afind_instance
@@ -120,88 +121,222 @@ class Module:
120121
def __contains__(self, cls: _InputType[Any], /) -> bool: ...
121122
@property
122123
def is_locked(self) -> bool: ...
124+
@overload
123125
def inject[**P, T](
124126
self,
125-
wrapped: Callable[P, T] = ...,
127+
wrapped: Callable[P, T],
126128
/,
127129
*,
128130
threadsafe: bool | None = ...,
129-
) -> Any:
131+
) -> Callable[P, T]:
130132
"""
131133
Decorator applicable to a class or function. Inject function dependencies using
132134
parameter type annotations. If applied to a class, the dependencies resolved
133135
will be those of the `__init__` method.
134136
135137
With `threadsafe=True`, the injection logic is wrapped in a `threading.RLock`.
136138
"""
137-
139+
@overload
140+
def inject[T](
141+
self,
142+
wrapped: type[T],
143+
/,
144+
*,
145+
threadsafe: bool | None = ...,
146+
) -> type[T]: ...
147+
@overload
148+
def inject[**P, T](
149+
self,
150+
wrapped: None = ...,
151+
/,
152+
*,
153+
threadsafe: bool | None = ...,
154+
) -> _Decorator[Callable[P, T]] | _Decorator[type[T]]: ...
155+
@overload
138156
def injectable[**P, T](
139157
self,
140-
wrapped: _Recipe[P, T] = ...,
158+
wrapped: Callable[P, T],
141159
/,
142160
*,
143161
cls: _InjectableFactory[T] = ...,
144162
inject: bool = ...,
145163
on: _TypeInfo[T] = ...,
146164
mode: Mode | ModeStr = ...,
147-
) -> Any:
165+
) -> Callable[P, T]:
148166
"""
149167
Decorator applicable to a class or function. It is used to indicate how the
150168
injectable will be constructed. At injection time, a new instance will be
151169
injected each time.
152170
"""
153171

172+
@overload
173+
def injectable[**P, T]( # type: ignore[overload-overlap]
174+
self,
175+
wrapped: Callable[P, Awaitable[T]],
176+
/,
177+
*,
178+
cls: _InjectableFactory[T] = ...,
179+
inject: bool = ...,
180+
on: _TypeInfo[T] = ...,
181+
mode: Mode | ModeStr = ...,
182+
) -> Callable[P, Awaitable[T]]: ...
183+
@overload
184+
def injectable[T](
185+
self,
186+
wrapped: type[T],
187+
/,
188+
*,
189+
cls: _InjectableFactory[T] = ...,
190+
inject: bool = ...,
191+
on: _TypeInfo[T] = ...,
192+
mode: Mode | ModeStr = ...,
193+
) -> type[T]: ...
194+
@overload
195+
def injectable[**P, T](
196+
self,
197+
wrapped: None = ...,
198+
/,
199+
*,
200+
cls: _InjectableFactory[T] = ...,
201+
inject: bool = ...,
202+
on: _TypeInfo[T] = ...,
203+
mode: Mode | ModeStr = ...,
204+
) -> (
205+
_Decorator[Callable[P, T]]
206+
| _Decorator[Callable[P, Awaitable[T]]]
207+
| _Decorator[type[T]]
208+
): ...
209+
@overload
154210
def singleton[**P, T](
155211
self,
156-
wrapped: _Recipe[P, T] = ...,
212+
wrapped: Callable[P, T],
157213
/,
158214
*,
159215
inject: bool = ...,
160216
on: _TypeInfo[T] = ...,
161217
mode: Mode | ModeStr = ...,
162-
) -> Any:
218+
) -> Callable[P, T]:
163219
"""
164220
Decorator applicable to a class or function. It is used to indicate how the
165221
singleton will be constructed. At injection time, the injected instance will
166222
always be the same.
167223
"""
168224

169-
def scoped[T](
225+
@overload
226+
def singleton[**P, T]( # type: ignore[overload-overlap]
227+
self,
228+
wrapped: Callable[P, Awaitable[T]],
229+
/,
230+
*,
231+
inject: bool = ...,
232+
on: _TypeInfo[T] = ...,
233+
mode: Mode | ModeStr = ...,
234+
) -> Callable[P, Awaitable[T]]: ...
235+
@overload
236+
def singleton[T](
237+
self,
238+
wrapped: type[T],
239+
/,
240+
*,
241+
inject: bool = ...,
242+
on: _TypeInfo[T] = ...,
243+
mode: Mode | ModeStr = ...,
244+
) -> type[T]: ...
245+
@overload
246+
def singleton[**P, T](
247+
self,
248+
wrapped: None = ...,
249+
/,
250+
*,
251+
inject: bool = ...,
252+
on: _TypeInfo[T] = ...,
253+
mode: Mode | ModeStr = ...,
254+
) -> (
255+
_Decorator[Callable[P, T]]
256+
| _Decorator[Callable[P, Awaitable[T]]]
257+
| _Decorator[type[T]]
258+
): ...
259+
def scoped[**P, T](
170260
self,
171261
scope_name: str,
172262
/,
173263
*,
174264
inject: bool = ...,
175265
on: _TypeInfo[T] = (),
176266
mode: Mode | ModeStr = ...,
177-
) -> Any:
267+
) -> (
268+
_Decorator[Callable[P, T]]
269+
| _Decorator[Callable[P, Awaitable[T]]]
270+
| _Decorator[Callable[P, AsyncIterator[T]]]
271+
| _Decorator[Callable[P, Iterator[T]]]
272+
| _Decorator[type[T]]
273+
):
178274
"""
179275
Decorator applicable to a class or function or generator function. It is used
180276
to indicate how the scoped instance will be constructed. At injection time, the
181277
injected instance is retrieved from the scope.
182278
"""
183279

184-
def should_be_injectable[T](self, wrapped: type[T] = ..., /) -> Any:
280+
@overload
281+
def should_be_injectable[T](self, wrapped: type[T], /) -> type[T]:
185282
"""
186283
Decorator applicable to a class. It is used to specify whether an injectable
187284
should be registered. Raise an exception at injection time if the class isn't
188285
registered.
189286
"""
190287

288+
@overload
289+
def should_be_injectable[T](
290+
self,
291+
wrapped: None = ...,
292+
/,
293+
) -> _Decorator[type[T]]: ...
294+
@overload
191295
def constant[**P, T](
192296
self,
193-
wrapped: _Recipe[P, T] = ...,
297+
wrapped: Callable[P, T],
194298
/,
195299
*,
196300
on: _TypeInfo[T] = ...,
197301
mode: Mode | ModeStr = ...,
198-
) -> Any:
302+
) -> Callable[P, T]:
199303
"""
200304
Decorator applicable to a class or function. It is used to indicate how the
201305
constant is constructed. At injection time, the injected instance will always
202306
be the same. Unlike `@singleton`, dependencies will not be resolved.
203307
"""
204308

309+
@overload
310+
def constant[**P, T]( # type: ignore[overload-overlap]
311+
self,
312+
wrapped: Callable[P, Awaitable[T]],
313+
/,
314+
*,
315+
on: _TypeInfo[T] = ...,
316+
mode: Mode | ModeStr = ...,
317+
) -> Callable[P, Awaitable[T]]: ...
318+
@overload
319+
def constant[T](
320+
self,
321+
wrapped: type[T],
322+
/,
323+
*,
324+
on: _TypeInfo[T] = ...,
325+
mode: Mode | ModeStr = ...,
326+
) -> type[T]: ...
327+
@overload
328+
def constant[**P, T](
329+
self,
330+
wrapped: None = ...,
331+
/,
332+
*,
333+
on: _TypeInfo[T] = ...,
334+
mode: Mode | ModeStr = ...,
335+
) -> (
336+
_Decorator[Callable[P, T]]
337+
| _Decorator[Callable[P, Awaitable[T]]]
338+
| _Decorator[type[T]]
339+
): ...
205340
def set_constant[T](
206341
self,
207342
instance: T,

injection/_core/common/type.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
Generator,
88
Iterable,
99
Iterator,
10+
Sequence,
1011
)
1112
from inspect import isfunction
1213
from types import GenericAlias, UnionType
@@ -26,7 +27,7 @@
2627
InputType[T]
2728
| Callable[..., T]
2829
| Callable[..., Awaitable[T]]
29-
| Iterable[TypeInfo[T]]
30+
| Sequence[TypeInfo[T]]
3031
)
3132

3233

injection/entrypoint.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,20 @@
2222
]
2323

2424

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]
25+
@overload
26+
def autocall[T: Callable[..., Any]](wrapped: T, /) -> T: ...
27+
28+
29+
@overload
30+
def autocall[T: Callable[..., Any]](wrapped: None = ..., /) -> Callable[[T], T]: ...
31+
32+
33+
def autocall[T: Callable[..., Any]](
34+
wrapped: T | None = None,
35+
/,
36+
) -> T | Callable[[T], T]:
37+
def decorator(wp: T) -> T:
38+
wp()
2839
return wp
2940

3041
return decorator(wrapped) if wrapped else decorator

0 commit comments

Comments
 (0)