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

Arg-type warning calling dataclasses.replace() with **dict for keyword arguments. #15994

Closed
flaviovs opened this issue Aug 30, 2023 · 4 comments
Labels
bug mypy got something wrong topic-dataclasses

Comments

@flaviovs
Copy link

Bug Report

Calling dataclasses.replace() using a dict for dynamic arguments issues arg-type warnings.

To Reproduce

from dataclasses import dataclass, replace

@dataclass
class Foo:
    bar: str
    zee: int

obj1 = Foo(bar='abc', zee=1)

kwargs = {'bar': 'xyz', 'zee': 9}
obj2 = replace(obj1, **kwargs)

print(obj1)
print(obj2)

Program output:

$ python /tmp/test.py 
Foo(bar='abc', zee=1)
Foo(bar='xyz', zee=9)

Expected Behavior

No warnings from mypy.

Actual Behavior

$ mypy /tmp/test.py 
/tmp/test.py:13: error: Argument 2 to "replace" of "Foo" has incompatible type "**dict[str, object]"; expected "str"  [arg-type]
/tmp/test.py:13: error: Argument 2 to "replace" of "Foo" has incompatible type "**dict[str, object]"; expected "int"  [arg-type]

$ mypy --version
mypy 1.5.1 (compiled: yes)

Apparently Mypy is trying to match each dict element type to class attributes (which is good), but not considering the fact that the 2nd parameter of replace() is a var-keyword therefore **dict is perfectly fine.

Your Environment

$ python --version
Python 3.9.2

$ mypy --version
mypy 1.5.1 (compiled: yes)
@flaviovs flaviovs added the bug mypy got something wrong label Aug 30, 2023
@sobolevn
Copy link
Member

cc @ikonst

@ikonst
Copy link
Contributor

ikonst commented Aug 31, 2023

We don't do custom arg validation for replace, we return a signature and have mypy validate it as it does with any other. The same thing happens if you take dataclasses out of it:
https://mypy-play.net/?mypy=latest&python=3.11&gist=ec706ef461064cf9fb54d8ab8df8d5b5

We have plenty of dups: #5382, #15317 - more can be found.

(Curiously pyright seems to handle it correctly, not sure what it does differently.)

@ikonst
Copy link
Contributor

ikonst commented Aug 31, 2023

OK, I was too quick to decide pyright handles it more correctly.

The difference is in Inference of List, Set, and Dict Expressions.

mypy infers {'bar': 'xyz', 'zee': 9} as dict[str, object], pyright infers as dict[str, Unknown], the latter is somewhat akin to Any. For example, this will be a false positive on pyright:

def f(*, a: int, b: str) -> None:
    return

f(**{'a': 42, 'b': True})

@AlexWaygood
Copy link
Member

Yeah, I agree with @ikonst that this is really just a dupe of #5382

@AlexWaygood AlexWaygood closed this as not planned Won't fix, can't repro, duplicate, stale Aug 31, 2023
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-dataclasses
Projects
None yet
Development

No branches or pull requests

4 participants