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

Mypy fails to detect missing keyword arguments when unpacking a TypedDict with NotRequired fields #15834

Open
canassa opened this issue Aug 9, 2023 · 2 comments
Labels
bug mypy got something wrong topic-typed-dict

Comments

@canassa
Copy link

canassa commented Aug 9, 2023

Bug Report

When using a TypedDict that contains fields marked with NotRequired from typing_extensions, and then unpacking this dictionary to pass it as keyword arguments to a function, Mypy does not raise an error even when mandatory keyword arguments are missing.

To Reproduce

The following playground contains an invalid Python code that Mypy is unable to detect any issues

https://mypy-play.net/?mypy=latest&python=3.11&gist=27aab8774484cff83b69d1659290ab09

from typing import TypedDict
from typing_extensions import NotRequired


# Creates a TypedDict with one optional property
class Params(TypedDict):
    a: str
    b: NotRequired[int]


# Defines a function with two mandatory keyword arguments
def func(*, a: str, b: int):
    pass


# Defines a dict with only the mandatory argument
params: Params = {"a": "a"}

# Tries to call the function with one missing argument
func(**params)  

Note: The same issue happens when using total=False

Expected Behavior

Mypy should raise an error if a function does not receive all its required arguments

Actual Behavior

Mypy is unable to detect any problems

Your Environment

  • Mypy version used: 1.4.1
  • Mypy command-line flags:
  • Mypy configuration options from mypy.ini (and other config files):
[tool.mypy]
python_version = "3.10"
check_untyped_defs = true
ignore_errors = false
ignore_missing_imports = true
strict_optional = true
warn_unused_ignores = true
warn_redundant_casts = true
warn_unused_configs = true
disallow_untyped_defs = false
enable_incomplete_feature = ["Unpack"]
plugins = [
    "pydantic.mypy",
]
  • Python version used: 3.10.12
@canassa canassa added the bug mypy got something wrong label Aug 9, 2023
@erictraut
Copy link

I think mypy is doing the right thing in this case.

When matching keyword parameters, a type checker needs to either assume that NotRequired keys are present or that they are not. It cannot generally know (statically) whether a NotRequired key is present. I think it's reasonable for mypy to assume that all NotRequred keys are present. (That's the same assumption pyright makes in this case.)

This approach reduces false positive errors, potentially at the expense of false negatives in some cases. This is consistent with the handling of an unpacked dict, which can also be missing some keys.

def func(*, a: str, b: str):
    pass

params: dict[str, str] = {"a": "a"}

func(**params) # No error reported by mypy

@ilevkivskyi
Copy link
Member

Note btw there is a flag --extra-checks (part of --strict), that has couple ~similar checks for e.g. TypedDict literals with {"foo": "bar", **other}, and TypedDict.update(). We may include such check there.

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

No branches or pull requests

4 participants