From 5489fd33f08fd93eff167eda84b00eeab939a419 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Fri, 17 Nov 2023 20:49:33 +0000 Subject: [PATCH] Fix crash on invalid enum in method (#16511) Fixes https://github.com/python/mypy/issues/16163 Fix is straightforward: I simply copy the logic we have for invalid TypedDicts/NamedTuples. --- mypy/semanal_enum.py | 11 +++++++---- test-data/unit/check-incremental.test | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/mypy/semanal_enum.py b/mypy/semanal_enum.py index cd11204c3bcc..528b0519cca1 100644 --- a/mypy/semanal_enum.py +++ b/mypy/semanal_enum.py @@ -106,16 +106,19 @@ class A(enum.Enum): items, values, ok = self.parse_enum_call_args(call, fullname.split(".")[-1]) if not ok: # Error. Construct dummy return value. - info = self.build_enum_call_typeinfo(var_name, [], fullname, node.line) + name = var_name + if is_func_scope: + name += "@" + str(call.line) + info = self.build_enum_call_typeinfo(name, [], fullname, node.line) else: name = cast(StrExpr, call.args[0]).value if name != var_name or is_func_scope: # Give it a unique name derived from the line number. name += "@" + str(call.line) info = self.build_enum_call_typeinfo(name, items, fullname, call.line) - # Store generated TypeInfo under both names, see semanal_namedtuple for more details. - if name != var_name or is_func_scope: - self.api.add_symbol_skip_local(name, info) + # Store generated TypeInfo under both names, see semanal_namedtuple for more details. + if name != var_name or is_func_scope: + self.api.add_symbol_skip_local(name, info) call.analyzed = EnumCallExpr(info, items, values) call.analyzed.set_line(call) info.line = node.line diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 806a585bff39..2c7d908c5f5b 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -6560,3 +6560,26 @@ class C: [out] [out2] tmp/a.py:3: note: Revealed type is "TypedDict('b.C.Hidden@5', {'x': builtins.int})" + +[case testNoIncrementalCrashOnInvalidEnumMethod] +import a +[file a.py] +from lib import TheClass +[file a.py.2] +from lib import TheClass +x: TheClass +reveal_type(x.enum_type) +[file lib.py] +import enum + +class TheClass: + def __init__(self) -> None: + names = ["foo"] + pyenum = enum.Enum('Blah', { # type: ignore[misc] + x.upper(): x + for x in names + }) + self.enum_type = pyenum +[out] +[out2] +tmp/a.py:3: note: Revealed type is "def (value: builtins.object) -> lib.TheClass.pyenum@6"