I wish to type-annotate a function that takes an AnyStr
argument that defaults to a str
and also returns an AnyStr
of the same type. However, if I write this:
from typing import AnyStr def func(s: AnyStr = ".") -> AnyStr: return s
then mypy fails with “Incompatible default for argument "s" (default has type "str", argument has type "bytes")
“.
I also tried splitting the code into a .py
and .pyi
file like so:
.py
file:
def func(s = "."): return s
.pyi
file:
from typing import AnyStr def func(s: AnyStr = ...) -> AnyStr: ...
… but I must be invoking mypy wrong, because it fails to type-check the invocations of func
; e.g., if I add func(42)
to the .py
file, mypy doesn’t complain.
What is the correct way to annotate my function and get the code to be completely type-checked?
Advertisement
Answer
Use None
as the default value, then inside the function use two casts: one to replace None
with “.” cast as an Optional[AnyStr]
, and one to cast the return value as an AnyStr
.
def func(s : AnyStr = None) -> AnyStr: if s is None: s = cast(Optional[AnyStr], ".") return cast(AnyStr, s)
EDIT: My original answer fails, as the type check ignores the concrete implementation:
One possibility is to use overload
to enumerate the two cases covered by AnyStr
:
from typing import overload @overload def func(s: str = ".") -> str: pass @overload def func(s: bytes) -> bytes: pass def func(s): return s