1 year ago
#378624
Marcel Wilson
Can type hinting infer type of class attribute from another?
There are subclasses that have the class attribute matcher_function
set to a function. During instantiation that function is called and sets another attribute matcher
. In all cases the return object of the matcher_function
is what matcher
gets set to.
Is it possible to create a type hint in the base class BaseResolution
that would allow both mypy and pycharm to properly infer matcher
is the return value of matcher_function
?
# contains_the_text.py
from hamcrest import contains_string
from hamcrest.library.text.stringcontains import StringContains
from .base_resolution import BaseResolution
class ContainsTheText(BaseResolution):
matcher: StringContains # <-- this is what I'm curious can be inferred
matcher_function = contains_string # <-- this function returns an instance
# of `StringContains`
# it would be wonderful if
# a. mypy could detect that the matcher type hint is correct based on 'matcher_function'
# b. infer what the type is when the hint is not present in the subclasses.
# base_resolution.py
from typing import Any, Callable, TypeVar
from hamcrest.core.base_matcher import BaseMatcher, Matcher
from hamcrest.core.description import Description
T = TypeVar("T")
class BaseResolution(BaseMatcher[T]):
matcher: Matcher
matcher_function: Callable
expected: Any
def __init__(self, *args: object, **kwargs: object) -> None:
cls = self.__class__
if args and kwargs:
self.expected = (args, kwargs)
self.matcher = cls.matcher_function(*args, **kwargs)
elif args:
self.expected = args if len(args) > 1 else args[0]
self.matcher = cls.matcher_function(*args)
elif kwargs:
self.expected = kwargs
self.matcher = cls.matcher_function(**kwargs)
else:
self.expected = True
self.matcher = cls.matcher_function()
def _matches(self, item: T) -> bool:
"""passthrough to the matcher's method."""
return self.matcher.matches(item)
# truncated a whole bunch of other methods...
While these are likely better typehints, they didn't seem to do the trick.
class BaseResolution(BaseMatcher[T]):
matcher: Matcher[T]
matcher_function: Callable[..., Matcher[T]]
I know you can do something sorta similar using TypeVar(bound=)
which will infer function return types based on arguments passed in. But I can't seem to figure out how (if even possible) to apply that at a class attribute level.
from typing import Type, TypeVar, Generic
T = TypeVar("T")
class Foo(Generic[T]):
...
class FooBar(Foo[T]):
...
F = TypeVar("F", bound=Foo) # any instance subclass of Foo
class MyClass(FooBar):
...
def bar(f: Type[F]) -> F:
...
def baz(f: Type[Foo]) -> Foo:
...
objx = bar(MyClass)
objy = baz(MyClass)
reveal_type(objx) # -> MyClass*
reveal_type(objy) # -> Foo[Any]
Given the above example I tried the following but that clearly isn't right.
F = TypeVar("F", bound=Matcher)
class BaseResolution(BaseMatcher[T]):
matcher: F
matcher_function: Callable[..., F]
# mypy returns
# Type variable "base_resolution.F" is unbound
python
python-3.x
type-hinting
mypy
0 Answers
Your Answer