Skip to content

Commit a2ab97b

Browse files
TH3CHARLiemsullivan
authored andcommitted
Produce error when assigning Enum or TypedDict as attribute (#8107)
1 parent bc3e9d4 commit a2ab97b

File tree

4 files changed

+29
-3
lines changed

4 files changed

+29
-3
lines changed

mypy/semanal.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2161,14 +2161,17 @@ def analyze_typeddict_assign(self, s: AssignmentStmt) -> bool:
21612161
"""Check if s defines a typed dict."""
21622162
if isinstance(s.rvalue, CallExpr) and isinstance(s.rvalue.analyzed, TypedDictExpr):
21632163
return True # This is a valid and analyzed typed dict definition, nothing to do here.
2164-
if len(s.lvalues) != 1 or not isinstance(s.lvalues[0], NameExpr):
2164+
if len(s.lvalues) != 1 or not isinstance(s.lvalues[0], (NameExpr, MemberExpr)):
21652165
return False
21662166
lvalue = s.lvalues[0]
21672167
name = lvalue.name
21682168
is_typed_dict, info = self.typed_dict_analyzer.check_typeddict(s.rvalue, name,
21692169
self.is_func_scope())
21702170
if not is_typed_dict:
21712171
return False
2172+
if isinstance(lvalue, MemberExpr):
2173+
self.fail("TypedDict type as attribute is not supported", lvalue)
2174+
return False
21722175
# Yes, it's a valid typed dict, but defer if it is not ready.
21732176
if not info:
21742177
self.mark_incomplete(name, lvalue, becomes_typeinfo=True)

mypy/semanal_enum.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from mypy.nodes import (
99
Expression, Context, TypeInfo, AssignmentStmt, NameExpr, CallExpr, RefExpr, StrExpr,
1010
UnicodeExpr, TupleExpr, ListExpr, DictExpr, Var, SymbolTableNode, MDEF, ARG_POS,
11-
EnumCallExpr
11+
EnumCallExpr, MemberExpr
1212
)
1313
from mypy.semanal_shared import SemanticAnalyzerInterface
1414
from mypy.options import Options
@@ -25,13 +25,16 @@ def process_enum_call(self, s: AssignmentStmt, is_func_scope: bool) -> bool:
2525
Return True if this looks like an Enum definition (but maybe with errors),
2626
otherwise return False.
2727
"""
28-
if len(s.lvalues) != 1 or not isinstance(s.lvalues[0], NameExpr):
28+
if len(s.lvalues) != 1 or not isinstance(s.lvalues[0], (NameExpr, MemberExpr)):
2929
return False
3030
lvalue = s.lvalues[0]
3131
name = lvalue.name
3232
enum_call = self.check_enum_call(s.rvalue, name, is_func_scope)
3333
if enum_call is None:
3434
return False
35+
if isinstance(lvalue, MemberExpr):
36+
self.fail("Enum type as attribute is not supported", lvalue)
37+
return False
3538
# Yes, it's a valid Enum definition. Add it to the symbol table.
3639
self.api.add_symbol(name, enum_call, s)
3740
return True

test-data/unit/check-enum.test

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,3 +908,12 @@ def func(x: Union[int, None, Empty] = _empty) -> int:
908908
reveal_type(x) # N: Revealed type is 'builtins.int'
909909
return x + 2
910910
[builtins fixtures/primitives.pyi]
911+
912+
[case testAssignEnumAsAttribute]
913+
from enum import Enum
914+
915+
class A:
916+
def __init__(self) -> None:
917+
self.b = Enum("x", [("foo", "bar")]) # E: Enum type as attribute is not supported
918+
919+
reveal_type(A().b) # N: Revealed type is 'Any'

test-data/unit/check-typeddict.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,3 +1987,14 @@ reveal_type(foo['bar']) # N: Revealed type is 'builtins.list[Any]'
19871987
reveal_type(foo['baz']) # N: Revealed type is 'builtins.list[Any]'
19881988
[builtins fixtures/dict.pyi]
19891989
[typing fixtures/typing-full.pyi]
1990+
1991+
[case testAssignTypedDictAsAttribute]
1992+
from typing import TypedDict
1993+
1994+
class A:
1995+
def __init__(self) -> None:
1996+
self.b = TypedDict('b', {'x': int, 'y': str}) # E: TypedDict type as attribute is not supported
1997+
1998+
reveal_type(A().b) # N: Revealed type is 'Any'
1999+
[builtins fixtures/dict.pyi]
2000+
[typing fixtures/typing-full.pyi]

0 commit comments

Comments
 (0)