Type checking a method call with a default argument prior to keyword argument dictionary

Question:

Given

def f_with_opt(opt_arg: bool | None = None, **kwargs):
    print(f"{opt_arg=}, {kwargs=}")


def function() -> None:
    kwargs = {"foo": "bar"}
    f_with_opt(**kwargs)  # mypy complains about this line


if __name__ == "__main__":
    function()


mypy reports

test.py:7:18: error: Argument 1 to "f_with_opt" has incompatible type "**Dict[str, str]"; expected "Optional[bool]"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

How can I properly annotate the methods to avoid this error? I’ve taken a look at https://peps.python.org/pep-0612/ but I don’t think it helps in this case. Or does it?

Asked By: JuanT

||

Answers:

Searching a bit I came across this GitHub issue: https://github.com/python/mypy/issues/5382

And so following this issue, you can fix simply by typing your dictionary with dict[str, Any]
Ex:

    kwargs: dict[str, Any] = {"foo": "bar"}

Or you can create a TypedDict, but depending on what you want to do with your dictionary this may seem a bit overkill.

Answered By: Jay

To properly annotate the methods and avoid the error, you need to use typing.Dict and typing.Union types in the method definition, like this:

from typing import Dict, Union

def f_with_opt(opt_arg: Union[bool, None] = None, **kwargs: Dict[str, str]):
    print(f"{opt_arg=}, {kwargs=}")

or use ** in the function definition like this:

def f_with_opt(opt_arg: Union[bool, None] = None, *, **kwargs: Dict[str, str]):
    print(f"{opt_arg=}, {kwargs=}")

This way, mypy will understand that the **kwargs argument should be a dictionary of keyword arguments and that the opt_arg argument should be of type bool or None.

Answered By: Hamed Fuladi
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.