Finistere / antidote

Dependency injection for Python
MIT License
90 stars 9 forks source link

Alternative injection styles don't pass mypy #60

Closed pauleveritt closed 2 years ago

pauleveritt commented 2 years ago

In the Injection Tutorial we have different flavors of injection. Here's a rewritten version:

@inject
def annotation_greeting(greeter: Inject[Greeter]) -> str:
    """Use a PEP 593 ``Annotation``, in this case, ``Inject``."""
    return f"{greeter.salutation}!"

@inject([Greeter])
def list_greeting(greeter: Greeter) -> str:
    """Synchronize the decorator and function arguments with a list."""
    return f"{greeter.salutation}!"

@inject(dict(greeter=Greeter))
def dict_greeting(greeter: Greeter) -> str:
    """Synchronize the decorator and function arguments with a dict."""
    return f"{greeter.salutation}!"

mypy says:

src/antidote_book/different_spellings/__init__.py:54:12: error: Missing positional argument "greeter"
in call to "annotation_greeting"  [call-arg]
        return annotation_greeting(), list_greeting(), dict_greeting()
               ^
src/antidote_book/different_spellings/__init__.py:54:35: error: Missing positional argument "greeter"
in call to "list_greeting"  [call-arg]
        return annotation_greeting(), list_greeting(), dict_greeting()
                                      ^
src/antidote_book/different_spellings/__init__.py:54:52: error: Missing positional argument "greeter"
in call to "dict_greeting"  [call-arg]
        return annotation_greeting(), list_greeting(), dict_greeting()
                                                       ^
Finistere commented 2 years ago

Unfortunately, there's no way to handle this. At least none that I'm aware of. The only possible modification of the ParamSpec (PEP-612) is concatenation. I can't specify that arguments have now default values. And even if it could be possible, I would also need to be able to identify at compile/import time which arguments you're injecting...

That's why I've added the notation with the default argument (inject.me, inject.get currently). It's the only one working nicely with mypy.

pauleveritt commented 2 years ago

Good enough, we'll close this. Sorry for two posts, wasn't sure if they should be exactly the same topic.