Skip to content

DefaultDict of a TypedDict confuses mypy #7217

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

Open
kaste opened this issue Jul 15, 2019 · 4 comments
Open

DefaultDict of a TypedDict confuses mypy #7217

kaste opened this issue Jul 15, 2019 · 4 comments
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-typed-dict

Comments

@kaste
Copy link

kaste commented Jul 15, 2019

Hi 👋 ! I have the following test code:

from collections import defaultdict

from typing import DefaultDict
from mypy_extensions import TypedDict

RepoPath = str
RepoStatus = TypedDict('RepoStatus', {
    'branch': str,
    'remote': str,
    'clean': bool,
    # ...
}, total=False)

State2 = defaultdict(RepoStatus)            # type: DefaultDict[RepoPath, RepoStatus]
State3 = defaultdict(dict)                  # type: DefaultDict[RepoPath, RepoStatus]
State4 = defaultdict(lambda: RepoStatus())  # type: DefaultDict[RepoPath, RepoStatus]
State5 = defaultdict(lambda: dict())        # type: DefaultDict[RepoPath, RepoStatus]
State6 = defaultdict(lambda: {})            # type: DefaultDict[RepoPath, RepoStatus]

mypy only accepts the definition of 4 and 6. A pic is easy to follow here

image

mypy output:

 16:10  error  mypy  Argument 1 to "defaultdict" has incompatible type "Type[RepoStatus]"; expected
                     "Optional[Callable[[], RepoStatus]]"
 17:10  error  mypy  Argument 1 to "defaultdict" has incompatible type "Type[Dict[Any, Any]]";
                     expected "Optional[Callable[[], RepoStatus]]"
 19:10  error  mypy  Argument 1 to "defaultdict" has incompatible type "Callable[[], Dict[<nothing>,
                     <nothing>]]"; expected "Optional[Callable[[], RepoStatus]]"
 19:22  error  mypy  Incompatible return value type (got "Dict[<nothing>, <nothing>]", expected
                     "RepoStatus")

Ideally the def of State3, just defaultdict(dict), should work, shouldn't it? It is also very surprising that there is a difference between 5 and 6.

mypy 0.720

@JukkaL JukkaL added bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-typed-dict labels Jul 17, 2019
@JukkaL
Copy link
Collaborator

JukkaL commented Jul 17, 2019

Yeah, it would be nice if all the cases would be supported by mypy. I think that at least case 5 could be easy to support. 2 and 3 might be harder or require more ad hoc changes.

And thanks for the detailed report!

@tqa236
Copy link

tqa236 commented Mar 25, 2020

Hello there, any update on this issue? Thank you very much.

kaustubh-nair added a commit to kaustubh-nair/zulip-terminal that referenced this issue Jun 29, 2020
Having a nested function allows us to discontinue the use of the `key`
variable which can be useful if multiple sections of unread_counts need
to be updated for a message type.

It includes type annotation changes such as:

* `key` passed into the nested function is typed using TypeVar.
* Message has been typed using a TypedDict so that mypy can determine
  the type of `key`. Note the use of Totality here because stream
  messages/pms/huddles do not have the same attributes. This change
  cannot be split into a prior commit because that will require
  multiple type definitions of the same `key` variable.
* An alternate declaration of `messages` in initial_index is necessary
  due to a mypy bug - python/mypy#7217 - while
  using TypeDict with defaultdict.
kaustubh-nair added a commit to kaustubh-nair/zulip-terminal that referenced this issue Jun 30, 2020
Note the use of Totality here because stream messages/pms/huddles
do not have the same attributes.

An alternate declaration of `messages` in initial_index is necessary
due to a mypy bug - python/mypy#7217 - while
using TypeDict with defaultdict.
kaustubh-nair added a commit to kaustubh-nair/zulip-terminal that referenced this issue Jun 30, 2020
Note the use of Totality here because stream messages/pms/huddles
do not have the same attributes.

An alternate declaration of `messages` in initial_index is necessary
due to a mypy bug - python/mypy#7217 - while
using TypeDict with defaultdict.
kaustubh-nair added a commit to kaustubh-nair/zulip-terminal that referenced this issue Jun 30, 2020
Note the use of Totality here because stream messages/pms/huddles
do not have the same attributes.

An alternate declaration of `messages` in initial_index is necessary
due to a mypy bug - python/mypy#7217 - while
using TypeDict with defaultdict.
kaustubh-nair added a commit to kaustubh-nair/zulip-terminal that referenced this issue Jun 30, 2020
Note the use of Totality here because stream messages/pms/huddles
do not have the same attributes.

An alternate declaration of `messages` in initial_index is necessary
due to a mypy bug - python/mypy#7217 - while
using TypeDict with defaultdict.
neiljp pushed a commit to zulip/zulip-terminal that referenced this issue Jun 30, 2020
Note the absence of Totality here because stream messages/pms/huddles
do not have the same attributes.

An alternate declaration of `messages` in initial_index is necessary
due to a mypy bug - python/mypy#7217 - while
using TypeDict with defaultdict.
@97littleleaf11
Copy link
Collaborator

There is no error message for State5 now.

@ilevkivskyi
Copy link
Member

I just checked that with my PR #19254 everything except State3 works (that one will require some hardcore special-casing probably).

ilevkivskyi added a commit that referenced this issue Jun 9, 2025
Fixes #3832
Fixes #5723
Fixes #17174
Improves #7217

This is a sixth "major" PR toward
#7724. Previously access to
"static" attributes (like type aliases, class objects) was duplicated in
four places:
* In `analyze_ref_expr()`
* In `determine_type_of_member()` (for modules as subtypes of protocols)
* In instance attribute access logic
* In class attribute logic

Most of these were somewhat incomplete and/or inconsistent, this PR
unifies all four (there is still tiny duplication because I decided to
limit the number of deferrals, i.e. preserve the existing logic in this
respect). Some notable things that are not pure refactoring:
* Previously we disabled access to type variables as class attributes.
This was inconsistent with plain references and instance attributes that
just return `Instance("typing.TypeVar")`.
* Instance access plugins were only applied on `TypeInfo`s and
`TypeAlias`es, now they are applied always.
* Previously arguments kinds were sometimes not correct for TypedDict
class objects with non-required keys.
* I tweaked `TypeOfAny` in couple places to be more logical.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal topic-typed-dict
Projects
None yet
Development

No branches or pull requests

5 participants