Skip to content
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

Produce error when assigning Enum or TypedDict as attribute #8107

Merged
merged 1 commit into from
Dec 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2161,14 +2161,17 @@ def analyze_typeddict_assign(self, s: AssignmentStmt) -> bool:
"""Check if s defines a typed dict."""
if isinstance(s.rvalue, CallExpr) and isinstance(s.rvalue.analyzed, TypedDictExpr):
return True # This is a valid and analyzed typed dict definition, nothing to do here.
if len(s.lvalues) != 1 or not isinstance(s.lvalues[0], NameExpr):
if len(s.lvalues) != 1 or not isinstance(s.lvalues[0], (NameExpr, MemberExpr)):
return False
lvalue = s.lvalues[0]
name = lvalue.name
is_typed_dict, info = self.typed_dict_analyzer.check_typeddict(s.rvalue, name,
self.is_func_scope())
if not is_typed_dict:
return False
if isinstance(lvalue, MemberExpr):
self.fail("TypedDict type as attribute is not supported", lvalue)
return False
# Yes, it's a valid typed dict, but defer if it is not ready.
if not info:
self.mark_incomplete(name, lvalue, becomes_typeinfo=True)
Expand Down
7 changes: 5 additions & 2 deletions mypy/semanal_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from mypy.nodes import (
Expression, Context, TypeInfo, AssignmentStmt, NameExpr, CallExpr, RefExpr, StrExpr,
UnicodeExpr, TupleExpr, ListExpr, DictExpr, Var, SymbolTableNode, MDEF, ARG_POS,
EnumCallExpr
EnumCallExpr, MemberExpr
)
from mypy.semanal_shared import SemanticAnalyzerInterface
from mypy.options import Options
Expand All @@ -25,13 +25,16 @@ def process_enum_call(self, s: AssignmentStmt, is_func_scope: bool) -> bool:
Return True if this looks like an Enum definition (but maybe with errors),
otherwise return False.
"""
if len(s.lvalues) != 1 or not isinstance(s.lvalues[0], NameExpr):
if len(s.lvalues) != 1 or not isinstance(s.lvalues[0], (NameExpr, MemberExpr)):
return False
lvalue = s.lvalues[0]
name = lvalue.name
enum_call = self.check_enum_call(s.rvalue, name, is_func_scope)
if enum_call is None:
return False
if isinstance(lvalue, MemberExpr):
self.fail("Enum type as attribute is not supported", lvalue)
return False
# Yes, it's a valid Enum definition. Add it to the symbol table.
self.api.add_symbol(name, enum_call, s)
return True
Expand Down
9 changes: 9 additions & 0 deletions test-data/unit/check-enum.test
Original file line number Diff line number Diff line change
Expand Up @@ -908,3 +908,12 @@ def func(x: Union[int, None, Empty] = _empty) -> int:
reveal_type(x) # N: Revealed type is 'builtins.int'
return x + 2
[builtins fixtures/primitives.pyi]

[case testAssignEnumAsAttribute]
from enum import Enum

class A:
def __init__(self) -> None:
self.b = Enum("x", [("foo", "bar")]) # E: Enum type as attribute is not supported

reveal_type(A().b) # N: Revealed type is 'Any'
11 changes: 11 additions & 0 deletions test-data/unit/check-typeddict.test
Original file line number Diff line number Diff line change
Expand Up @@ -1987,3 +1987,14 @@ reveal_type(foo['bar']) # N: Revealed type is 'builtins.list[Any]'
reveal_type(foo['baz']) # N: Revealed type is 'builtins.list[Any]'
[builtins fixtures/dict.pyi]
[typing fixtures/typing-full.pyi]

[case testAssignTypedDictAsAttribute]
from typing import TypedDict

class A:
def __init__(self) -> None:
self.b = TypedDict('b', {'x': int, 'y': str}) # E: TypedDict type as attribute is not supported

reveal_type(A().b) # N: Revealed type is 'Any'
[builtins fixtures/dict.pyi]
[typing fixtures/typing-full.pyi]