ivankorobkov / python-inject

Python dependency injection
Apache License 2.0
671 stars 77 forks source link

How to fix type errors? #102

Open Spoonrad opened 2 months ago

Spoonrad commented 2 months ago

How can I fix typing errors when using this library?

Example:

from abc import ABC, abstractmethod

import inject

class ICache(ABC):

    @abstractmethod
    def check(self) -> bool:
        ...

class Cache(ICache):
    ...

    def check(self) -> bool:
        return True

def test_inject() -> None:

    inject.configure(lambda binder: binder.bind(ICache, Cache()))  # type: ignore[arg-type]
    cache = inject.instance(ICache)
    cache.check()
mypy tests/test_inject.py
tests\test_inject.py:22: error: Item "object" of "object | Any" has no attribute "check"  [union-attr]

If I specify the type like this: cache: ICache I get an assignment error instead. How can I resolve this please?

etsvetanov commented 1 month ago

I don't think it's currently possible. I believe this happens because of the overloaded inject.instance()

Injectable = Union[object, Any]
# ....
@overload
def instance(cls: Hashable) -> Injectable: ...

And I suppose most things are considered "hashable":

In [1]: from abc import ABC, abstractmethod

In [2]: class ICache(ABC):
   ...:
   ...:     @abstractmethod
   ...:     def check(self) -> bool:
   ...:         ...
   ...:

In [3]: from collections.abc import Hashable

In [4]: issubclass(ICache, Hashable)
Out[4]: True

My understanding is that inject allows to bind to any "hashable" for convenience but maybe there should be a more specific type for binding to an arbitrary object/value?

Spoonrad commented 1 month ago

Doesn't look too difficult to fix given how broad the type spec currently is. Something like this should work:

InjectableTypeVar = TypeVar("InjectableTypeVar")

@overload
def instance(cls: type[InjectableTypeVar]) -> InjectableTypeVar:
   ...