python-dependency-injector
python-dependency-injector copied to clipboard
Add type checks for provider arguments (ParamSpec)
This feature is to support type checks for provider arguments.
The technical possibility to implement it comes with Python 3.10 ParamSpec
feature. Details: PEP 612: Parameter Specification Variables.
User suggestions:
For type hinting the arguments to a provider, was the decision, and perhaps the only option, to wait until Python 3.10 and the ParamSpec feature? Taking the below example, it would be useful to be able to use mypy to ensure all arguments and proper types are supplied to ApiClient and Service.
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
api_client = providers.Singleton(
ApiClient,
api_key=config.api_key,
timeout=config.timeout.as_int(),
)
service = providers.Factory(
Service,
api_client=api_client,
)
Originally posted by @dbertouille in https://github.com/ets-labs/python-dependency-injector/issues/268#issuecomment-717633173
What I would really look forward to would be type safety when creating the object graph / the providers. I believe that should be possible once ParamSpec lands in Python. Then one could consider doing something like.
P = ParamSpec("P")
R = TypeVar("R")
def factory(cls: Callable[P, R]) -> Callable[P, R]
and use it like
a = providers.factory(A)(arg1, kwarg1=42)
Originally posted by @JarnoRFB in https://github.com/ets-labs/python-dependency-injector/issues/268#issuecomment-675409193
I think that this feature can't be implemented via ParamSpec
def factory(cls: Callable[P, R]) -> Callable[P, R]
For example, this signature is actually invalid. The factory provider does not have the same args and kwargs that has the callable passed to it as the first argument. We expect that all args passed to the factory are providers too. And we can't use the PEP612 syntax to specify it.
@Paul-Ilyin thanks for clarifying, it looks like you are indeed right and I was a bit too optimistic with this feature. What we would actually need is the ability to transform the signature, like you can do with Mapped Types in typescript https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types . We might still keep an open eye for such a feature coming around or actively ask for it on the Python mailing list or something.
I found this issue and I think it's related to my problem: I want mypy to check the types in provider constructors to match the types of the constructor of the class. For now I can't achieve it (example below)
from dependency_injector.providers import Singleton
class Foo:
def __init__(self, x: int) -> None:
self.__x = x
def stuff(self, y: int) -> int:
return self.__x * y
provider = Singleton(Foo, "hello") # mypy says OK, should yield an error as for a call below
foo = Foo("hey") # mypy error: Argument 1 to "Foo" has incompatible type "str"; expected "int" [arg-type]
if __name__ == "__main__":
print(provider().stuff(10))
python -m mypy mycontainer.py
mycontainer.py:13:11: error: Argument 1 to "Foo" has incompatible type "str";
expected "int" [arg-type]
foo = Foo("hey")
^
Found 1 error in 1 file (checked 1 source file)
libs:
$ poetry show mypy; poetry show dependency-injector
name : mypy
version : 0.910
description : Optional static typing for Python
dependencies
- mypy-extensions >=0.4.3,<0.5.0
- toml *
- typing-extensions >=3.7.4
name : dependency-injector
version : 4.40.0
description : Dependency injection framework for Python
dependencies
- six >=1.7.0,<=1.16.0
I think this is very critical feature for dependency-injector lib. I didn't find a way to enable this kind of checks in the project, so I guess it's not supported yet. In my opinion we can add the support for type checks via mypy plugin (similar to pydantic lib). Can I help with that feature?
fyi, I've started to work on it. I found that this issue is similar to https://github.com/python/mypy/issues/1484 , because providers act like a partial function which is called then on class instantiation. I found a really good example of partial mypy support in returns library (see https://github.com/python/mypy/issues/1484#issuecomment-625423210), so I think it won't be a big deal to implement better provider types in this lib.