Skip to content

Add type checks for provider arguments (ParamSpec) #314

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
rmk135 opened this issue Oct 28, 2020 · 4 comments
Open

Add type checks for provider arguments (ParamSpec) #314

rmk135 opened this issue Oct 28, 2020 · 4 comments
Assignees
Labels

Comments

@rmk135
Copy link
Member

rmk135 commented Oct 28, 2020

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 #268 (comment)


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 #268 (comment)

@Paul-Ilyin
Copy link

Paul-Ilyin commented Feb 27, 2021

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.

@JarnoRFB
Copy link
Contributor

JarnoRFB commented Mar 3, 2021

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

@zerlok
Copy link

zerlok commented Aug 18, 2022

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
Copy link

zerlok commented Sep 15, 2022

fyi, I've started to work on it. I found that this issue is similar to python/mypy#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 python/mypy#1484 (comment)), so I think it won't be a big deal to implement better provider types in this lib.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants