Open zulrang opened 1 year ago
@zulrang Thanks for raising this issue, I think @inject decorator return types might need a fix. Will update you later on today on this.
Any update on this?
Any update on this?
I think this will be necessary: https://peps.python.org/pep-0612/
This is also problematic in PyCharm 2023.,2.
@zulrang were you able to figure out typing using PEP612 that seems to work in PyCharm / VSCode?
Perhaps something more simple (and backwards compatible) is possible using typing.overload
?
@overload
def inject(
_service: None = None,
alias: Any | None = None,
bind: Dict[str, Any] | None = None,
container: Container = di,
use_factory: bool = False) -> Callable[[ServiceDefinition], ServiceResult]: ...
@overload
def inject(
_service: ServiceDefinition,
alias: Any | None = None,
bind: Dict[str, Any] | None = None,
container: Container = di,
use_factory: bool = False) -> ServiceResult: ...
^Try this
Those overloads are not working for me in PyCharm.. Are they working for you in VSCode?
# Python version 3.11.4
from typing import Any, Callable, Type, TypeVar, cast, overload
from kink import Container as KinkContainer, di as kink_di, inject as kink_inject
from kink.inject import ServiceDefinition, ServiceResult
T = TypeVar("T")
class Container(KinkContainer):
@overload
def __getitem__(self, key: str) -> Any:
...
@overload
def __getitem__(self, key: Type[T]) -> T:
...
def __getitem__(self, key):
return super().__getitem__(key)
di = cast(Container, kink_di)
@overload
def inject(
_service: None = None,
alias: Any | None = None,
bind: dict[str, Any] | None = None,
container: Container = di,
use_factory: bool = False,
) -> Callable[[ServiceDefinition], ServiceResult]:
...
@overload
def inject(
_service: ServiceDefinition,
alias: Any | None = None,
bind: dict[str, Any] | None = None,
container: Container = di,
use_factory: bool = False,
) -> ServiceResult:
...
def inject(
_service: ServiceDefinition = None,
alias: Any = None,
bind: dict[str, Any] = None,
container: Container = di,
use_factory: bool = False,
):
return kink_inject(_service, alias, bind, container, use_factory)
@inject
class TestA:
def as_dict(self) -> dict:
return self.__dict__
@inject()
class TestB:
def as_dict(self) -> dict:
return self.__dict__
di[bytes].| # auto-complete -- but inject decorator not used
di[TestA].| # no auto-complete
di[TestB].| # no auto-complete
Those overloads are working for me in vscode
To clarify, those overloads fix the issue where mypy cannot resolve the return type of an injected function because the injected parameters are not being explicitly passed in.
It seems like the issue you're talking about might be different. I also do not get intellisense on the di container itself when doing di[TestA]
.
Adding inject overloads as well as overloads in your snippet to __getitem__
, as well as an additional overload to __setitem__
as follows appears to work in VS Code for autocomplete:
@overload
def __setitem__(self, key: Type[T], value: T) -> None:
...
@overload
def __setitem__(self, key: str, value: Any) -> None:
...
Played around in PyCharm a bit and this is what actually got type hinting working:
T = TypeVar("T")
@overload
def inject(
_service: None = None,
alias: Any | None = None,
bind: dict[str, Any] | None = None,
container: Container = di,
use_factory: bool = False,
) -> Callable[[T], T]:
...
# @overload
# def inject(
# _service = None,
# *,
# alias: Any | None = None,
# bind: dict[str, Any] | None = None,
# container: Container = di,
# use_factory: bool = False,
# ) -> Callable[[T], T]:
# ...
def inject(*args, **kwargs):
return kink_inject(*args, **kwargs)
If you un-comment the middle overload it breaks di[TestA]
type hinting.
@seanlossef-kce The Issue with intellisense from the container as of 0.7.0 should be fixed now (also added auto-wiring for optional types).
With inject solution I would like to play a bit with this. Unless anyone is willing to prepare a PR with tests, which would help me a lot as time is the essence ;)
Thanks for your understanding and support!
Any progress on the type hints for @inject? This issue is now over a year old.
For me, the typing hinting issues and mypy issues make kink unusable in projects and I am guessing many others feel the same. Nobody likes linter overrides all over their code.
@skewty I'd like to shed some light on the management and contribution process for this, and potentially other open-source projects. It's important to note that there's a limited number of contributors, particularly those offering improvements on the technical side. I'm not compensated anyway for the work I am doing here. My contributions are done in my personal time, outside of professional obligations and amidst other demands of life, which have been lately considerable.
This means my capacity to address problems, roll out new features, or respond quickly might be limited. However, I'm always open to contributions from the community. Since this is an open-source project, you're more than welcome to contribute by submitting your PR.
This code works with mypy:
While this code results in an error:
mypy error:
error: Incompatible types in "await" (actual type "Union[Any, Callable[..., Any]]", expected type "Awaitable[Any]")
Aside from ignoring the calling line, is there any way to make mypy happy with the type returned from the @inject decorator?