python-dependency-injector icon indicating copy to clipboard operation
python-dependency-injector copied to clipboard

Add type checks for provider arguments (ParamSpec)

Open rmk135 opened this issue 4 years ago • 4 comments

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

rmk135 avatar Oct 28 '20 16:10 rmk135

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 avatar Feb 27 '21 23:02 Paul-Ilyin

@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.

JarnoRFB avatar Mar 03 '21 19:03 JarnoRFB

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?

zerlok avatar Aug 18 '22 15:08 zerlok

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.

zerlok avatar Sep 15 '22 16:09 zerlok