Skip to content

Commit a2ab97b

Browse files
TH3CHARLiemsullivan
authored andcommitted
Produce error when assigning Enum or TypedDict as attribute (python#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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy