python-dependency-injector
python-dependency-injector copied to clipboard
[mypy] "Only concrete class can be given" fails with Dependency provider and abc
I'm trying to use Dependency provider according to the documentation, and the code works well, but mypy returns an error Only concrete class can be given where "Type[Animal]" is expected
. I found this mypy issue, but I'm not sure is that problem related to me. Should I comment to the mypy issue and wait for it to be solved in mypy?
import abc
from dependency_injector.containers import DeclarativeContainer
from dependency_injector.providers import Dependency, Factory
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def say(self) -> str:
raise NotImplementedError
class Dog(Animal):
def say(self) -> str:
return "bark"
class Container(DeclarativeContainer):
# mypy error: Only concrete class can be given where "Type[Animal]" is expected
animal_dependency = Dependency(Animal)
# no mypy errors
animal_factory = Factory(Animal)
def main() -> None:
container = Container()
container.animal_dependency.override(Factory(Dog))
container.animal_factory.override(Factory(Dog))
print(container.animal_dependency().say())
print(container.animal_factory().say())
if __name__ == "__main__":
main()
project dependencies
dependency-injector==4.36.0
mypy==0.910
mypy-extensions==0.4.3
six==1.16.0
toml==0.10.2
typing-extensions==3.10.0.0
mypy settings in project.toml
[tool.mypy]
python_version = "3.8"
disallow_any_unimported = true
disallow_any_decorated = true
disallow_any_generics = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
strict_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_return_any = true
warn_unreachable = true
strict_equality = true
implicit_reexport = false
show_error_context = true
show_column_numbers = true
show_error_codes = true
pretty = true
warn_unused_configs = true
Hi @zerlok. Yeah, this seems to be a mypy issue. There is no error on Factory
provider because it uses Callable[..., T]
instead of Type[T]
:
class Dependency(Provider[T]):
def __init__(self, instance_of: Type[T] = object, default: Optional[Union[Provider, Any]] = None) -> None: ...
class Factory(Provider[T]):
def __init__(self, provides: Optional[_Callable[..., T]] = None, *args: Injection, **kwargs: Injection) -> None: ...
Checked a bunch of different ideas but neither works. I'm sorry, I can not fix it in the Dependency Injector. I probably need to update the documentation removing abc usage.
Thanks for reporting the issue.
Hi, @ rmk135, thanks for response. I hope then mypy will fix it somehow. I leave the issue open by now. Also I think that you may add a simple note about mypy behavior in the docs, not removing abc usage (Dependency provider works as expected).
Hey, @rmk135 . The related mypy issue was closed. I tried to update mypy and dependency-injector and retry my code - the issue remains the same:
mycontainer.py: note: In class "Container":
mycontainer.py:20:36: error: Only concrete class can be given where
"Type[Animal]" is expected [misc]
animal_dependency = Dependency(Animal)
^
Found 1 error in 1 file (checked 1 source file)
Any ideas how to fix it?
Just an update, because this issue is top on google, there was some heated debates on mypy side about this because mypy allows for some behaviour where they need to ensure any instance of Type[X] is instanceable, so they can't allow an ABCs to fulfil Type[X] I didn't quite follow the details, but
TL;DR but there was some push back about this and the best people could agree on was moving the check behind its dedicated own error code (instead of the current misc) (this PR) that will be available on mypy 0.990 ~(not released at time of writing) after which we will be~ MyPy 0.990 has landed and we're able to purposefully ignore.
Current workaround I've been using is:
class Container(containers.DeclarativeContainer):
progress_monitoring = providers.Dependency(
# https://github.com/python/mypy/issues/5374
instance_of=ProgressMonitor, # type: ignore[type-abstract]
default=providers.Factory(
PubsubProgressMonitor,
tasks_lifecycle_topic=config.tasks_lifecycle_topic,
pubsub=pubsub,
),
)
Maybe add a mention to this to the MyPy section of the docs?