MyPy seems to be unaware of the length of a Tuple when wrapped in a Union:
from typing import Union, Tuple
def get_tuple() -> Union[Tuple[int, int], Tuple[None, None]]:
return (1, 2)
def process_tuple(one, two, flag=False):
print(one, two, flag)
process_tuple(*get_tuple(), flag=True)
1.py:12: error: "process_tuple" gets multiple values for keyword argument "flag"
Same code without a unionized type (def get_tuple() -> Tuple[int, int]:) works.
Oh, it looks like one more place where we need to special-case union types.
I think this is a pretty rare situation, so I set priority to low.
Updated priority to normal since this is a clear bug and we'd be happy to accept a PR that fixes this (at least if the fix is clean enough).
To add to the severity, consider this ubiquitous use case of initializing a constructor with custom keyword arguments:
from typing import Any
class Foo:
def __init__(self, a: str, b: str = 'Foo kwarg', c: str = 'Foo kwarg') -> None:
print(f"{a=} {b=} {c=}")
class Bar(Foo):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, b='Bar kwarg', **kwargs)
Bar('my arg')
# prints:
# a='my arg' b='Bar kwarg' c='Foo kwarg'
The above code is syntactically correct and runs fine, but mypy produces this on the super() line:
c:\Users\tim\code\blog-py\generator\foo.py:11: error: "__init__" of "Foo" gets multiple values for keyword argument "b"
For now, I will unfortunately # type: ignore this line in my code.
@t-mart technically I think it would be more correct to have Bar's init be:
def __init__(self, b='Bar kwarg', *args: Any, **kwargs: Any) -> None:
super().__init__(*args, b=b, **kwargs)
Since in your version above it would be possible to have multiple arguments for b passed to Foo. Unfortunately though, this re-writing still produces the same error.
As an additional example, quite common when some of the parameters are loaded from some external source and then you need to supply the rest of the parameters explicitly:
class MyClass:
def __init__(self, param1: str, param2: str, param3: str):
self.param1 = param1
self.param2 = param2
data = {"param1": "value1", "param2": "value2"} # coming from some external source
result = MyClass(**data, param3="value3")
would give
error: "MyClass" gets multiple values for keyword argument "param3"
@alexey-tereshenkov-oxb your example passes on mypy master :-)
@alexey-tereshenkov-oxb your example passes on mypy master :-)
Thanks for pinging :) I am on mypy 0.790
Most helpful comment
To add to the severity, consider this ubiquitous use case of initializing a constructor with custom keyword arguments:
The above code is syntactically correct and runs fine, but mypy produces this on the
super()line:For now, I will unfortunately
# type: ignorethis line in my code.