Skip to content

stubtest: treat dicts as a subtype of typeddict #12040

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

Merged
merged 3 commits into from
Jan 23, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions mypy/stubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,14 @@ def is_subtype_helper(left: mypy.types.Type, right: mypy.types.Type) -> bool:
# Pretend Literal[0, 1] is a subtype of bool to avoid unhelpful errors.
return True

if (
isinstance(right, mypy.types.TypedDictType)
and isinstance(left, mypy.types.Instance)
and left.type.fullname == "builtins.dict"
):
# Special case checks against TypedDicts
return True

with mypy.state.strict_optional_set(True):
return mypy.subtypes.is_subtype(left, right)

Expand Down
33 changes: 33 additions & 0 deletions mypy/test/teststubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,39 @@ def test_bad_literal(self) -> Iterator[Case]:
error='WRONG_BOOL_2',
)

@collect_cases
def test_special_subtype(self) -> Iterator[Case]:
yield Case(
stub="""
b1: bool
b2: bool
b3: bool
""",
runtime="""
b1 = 0
b2 = 1
b3 = 2
""",
error="b3",
)
yield Case(
stub="""
from typing_extensions import TypedDict

class _Options(TypedDict):
a: str
b: int

opt1: _Options
opt2: _Options
""",
runtime="""
opt1 = {"some": "stuff"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should fail if stubtest was smarter, let's make this a test case where it really should pass

Suggested change
opt1 = {"some": "stuff"}
opt1 = {"a": "stuff", "b": 4}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, did this to document the behaviour, but just added a third correct case

opt2 = 0
""",
error="opt2",
)


def remove_color_code(s: str) -> str:
return re.sub("\\x1b.*?m", "", s) # this works!
Expand Down