Coverage for nexios\dependencies.py: 89%
38 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-21 20:31 +0100
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-21 20:31 +0100
1from typing import Callable, Dict, List, Optional, Any
2from inspect import signature, Parameter
3from functools import wraps
4import inspect
7class Depend:
8 def __init__(self, dependency: Optional[Callable[..., Any]] = None):
9 self.dependency = dependency
11 def __class_getitem__(cls, item: Any):
12 return cls
15def inject_dependencies(handler: Callable[..., Any]) -> Callable[..., Any]:
16 """Decorator to inject dependencies into a route handler while preserving parameter names."""
18 @wraps(handler)
19 async def wrapped(*args: List[Any], **kwargs: Dict[str, Any]) -> Any:
20 sig = signature(handler)
21 bound_args = sig.bind_partial(*args, **kwargs)
23 # Get the parameters in order
24 params = list(sig.parameters.values())
26 for param in params:
27 if (
28 param.default != Parameter.empty
29 and isinstance(param.default, Depend)
30 and param.name not in bound_args.arguments
31 ):
32 depend = param.default
33 dependency_func = depend.dependency
35 if dependency_func is None:
36 raise ValueError(
37 f"Dependency for parameter '{param.name}' has no provider"
38 )
40 if hasattr(dependency_func, "__wrapped__"):
41 dependency_func = dependency_func.__wrapped__ # type: ignore[attr-defined]
43 dep_sig = signature(dependency_func)
44 dep_kwargs = {}
46 for dep_param in dep_sig.parameters.values():
47 if dep_param.name in bound_args.arguments:
48 dep_kwargs[dep_param.name] = bound_args.arguments[
49 dep_param.name
50 ]
51 elif dep_param.default != Parameter.empty and isinstance(
52 dep_param.default, Depend
53 ):
54 nested_dep = dep_param.default.dependency
55 if inspect.iscoroutinefunction(nested_dep):
56 dep_kwargs[dep_param.name] = await nested_dep()
57 else:
58 dep_kwargs[dep_param.name] = nested_dep() # type: ignore[attr-defined]
60 # Call the dependency
61 if inspect.iscoroutinefunction(dependency_func):
62 bound_args.arguments[param.name] = await dependency_func(
63 **dep_kwargs
64 )
65 else:
66 bound_args.arguments[param.name] = dependency_func(**dep_kwargs)
68 return await handler(**bound_args.arguments)
70 return wrapped