From 88ae1e4c1541e5b03d695cf63d1265b972e427d9 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Fri, 15 Sep 2023 21:53:35 +0100 Subject: [PATCH] Fix crash on star unpack in TypedDict (#16116) Fixes https://github.com/python/mypy/issues/16107 Fixes https://github.com/python/mypy/issues/15891 I only vaguely remember why I added those context managers, it seemed to me giving full TypedDict as context may cause false positives. But since the current way causes crashes, let's just not do this (we will see if there will be actual false positives). --- mypy/checkexpr.py | 3 +-- test-data/unit/check-typeddict.test | 12 ++++++++++ test-data/unit/reports.test | 34 +++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 22a9852545b7..f46c8cb15c6f 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -813,8 +813,7 @@ def validate_star_typeddict_item( Note `result` and `always_present_keys` are updated in place. Return true if the expression `item_arg` may valid in `callee` TypedDict context. """ - with self.chk.local_type_map(), self.msg.filter_errors(): - inferred = get_proper_type(self.accept(item_arg, type_context=callee)) + inferred = get_proper_type(self.accept(item_arg, type_context=callee)) possible_tds = [] if isinstance(inferred, TypedDictType): possible_tds = [inferred] diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index b8953f05b6a5..7ee9ef0b708b 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -3224,3 +3224,15 @@ t2: Foo = {**y} # E: Missing key "a" for TypedDict "Foo" t3: Foo = {**z} # E: Missing key "a" for TypedDict "Foo" [builtins fixtures/dict.pyi] [typing fixtures/typing-typeddict.pyi] + +[case testTypedDictUnpackError] +from typing import TypedDict + +class Foo(TypedDict): + a: int + +def foo(x: int) -> Foo: ... + +f: Foo = {**foo("no")} # E: Argument 1 to "foo" has incompatible type "str"; expected "int" +[builtins fixtures/dict.pyi] +[typing fixtures/typing-typeddict.pyi] diff --git a/test-data/unit/reports.test b/test-data/unit/reports.test index a6cde503ca09..16061d9c32bf 100644 --- a/test-data/unit/reports.test +++ b/test-data/unit/reports.test @@ -69,6 +69,40 @@ def untyped_function(): +[case testCoberturaStarUnpacking] +# cmd: mypy --cobertura-xml-report build a.py +[file a.py] +from typing import TypedDict + +class MyDict(TypedDict): + a: int + +def foo(a: int) -> MyDict: + return {"a": a} +md: MyDict = MyDict(**foo(42)) +[outfile build/cobertura.xml] + + + $PWD + + + + + + + + + + + + + + + + + + + [case testAnyExprReportDivisionByZero] # cmd: mypy --any-exprs-report=out -c 'pass'