Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misleading error when using a dict of keyword args #14073

Open
canepan opened this issue Nov 12, 2022 · 1 comment
Open

Misleading error when using a dict of keyword args #14073

canepan opened this issue Nov 12, 2022 · 1 comment
Labels
bug mypy got something wrong

Comments

@canepan
Copy link

canepan commented Nov 12, 2022

Bug Report

When passing at least part of the function parameter as an ** expanded dictionary, if one or more of the parameters is missing, a misleading "incomaptible type" is shown, instead of "missing parameter".
See also stackoverflow for a way to get a better (but still not correct, since it lists all the parameters as missing) message

To Reproduce

def my_func(a: str = 'Hello', b: bool = False, c: int = 1):
    return a, b, c


input_kwargs = {'b': True}
result = my_func(**input_kwargs)

or see the gist

Actual Behavior

main.py:14: error: Argument 1 to "fib" has incompatible type "**Dict[str, int]"; expected "str"
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 0.812 (or 0.981 on mypy-play)
  • Mypy command-line flags:
  • Mypy configuration options from mypy.ini (and other config files):
check_untyped_defs = True
show_error_codes = True
pretty = True
ignore_missing_imports = True
  • Python version used: 3.8 (or 3.10 on mypy-play)
@canepan canepan added the bug mypy got something wrong label Nov 12, 2022
@ikonst
Copy link
Contributor

ikonst commented Jan 27, 2023

This report is a bit misleading since it might appear that in the example, the problem is that mypy understands that input_kwargs provides parameter b but not a and c, which in practice input_kwargs is seen as an opaque dict[str, bool].

A simpler case is:

def f(*, foo: int, bar: bool) -> None:
    raise Exception
    

kw: dict[str, str] = {}
f(**kw)

Actual:

main.py:6: error: Argument 1 to "f" has incompatible type "**Dict[str, str]"; expected "int"  [arg-type]
main.py:6: error: Argument 1 to "f" has incompatible type "**Dict[str, str]"; expected "bool"  [arg-type]

Now, as to what's "expected", maybe something like this?

main.py:6: error: Argument 1 to "f" has incompatible type "**Dict[str, str]"; expected named arguments "(foo: int, bar: bool)"

or maybe, if we want to nudge users towards TypedDict:

... or a TypedDict:

  class ...(TypedDict):
     foo: int
     bar: bool

Playground URL: https://mypy-play.net/?gist=3d6875bd1447fe1b1259c3455155bea5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

2 participants