Let's say I have a class like this (pseudo-code, please ignore the odd db structure):
class Blog():
title = StringProperty()
comments = StringProperty(repeated=True)
I want to type check StringProperty such that Blog().title returns a str type, and Blog().comments returns a List[str] type. MyPy mentions that something like this is possible by dynamically typing the __init__ method.
Here's what I've tried:
U = TypeVar('U', bound=StringProperty)
V = TypeVar('V', bound=StringProperty)
class StringProperty(Property[T]):
@overload
def __init__(self: StringProperty[U], repeated: Literal[False]=False, **kwargs) -> None: ...
@overload
def __init__(self: StringProperty[V], repeated: Literal[True]=True, **kwargs) -> None: ...
@overload
def __get__(self: StringProperty[U], instance, cls) -> str: ...
@overload
def __get__(self: StringProperty[V], instance, cls) -> List[str]: ...
def __set__(self, instance, value: Optional[Union[str, List[str]]]) -> None: ...
However, this throws an error that the second __get__ type signature will never be matched. How can I set MyPy to know the return value of the StringProperty.__get__ method dynamically by whether the repeated property is True or False?
__init__can be overloaded.selfwill become the given type.TypeVarneeds to become some kind of real type during type analysis. It can't stay asTorUorV. It must be filled in with a type likestrorLiteral["foo"].Note that setting and reading
self._repeateddoes not aid in typing here in any way.StringPropertygets its type only from what types were passed to the constructor. If someone runsfalse_literal._repeated = True, thenfalse_literal.get()would return["Hello", "world!"], and the typing information is wrong.Using
strorlist[str]forStringProperty's type here was convenient. But the type can be less specific for weirder classes. Here we could've usedLiteral[True],Literal[False], andLiteral[True] | Literal[False]to represent the quality of being repeated. Thenget()would need overrides based on self to determine the return type.