Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Implement new NamedTuple syntax #2245

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

Merged
merged 5 commits into from
Oct 25, 2016
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 54 additions & 2 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
ImportFrom, ImportAll, Block, LDEF, NameExpr, MemberExpr,
IndexExpr, TupleExpr, ListExpr, ExpressionStmt, ReturnStmt,
RaiseStmt, AssertStmt, OperatorAssignmentStmt, WhileStmt,
ForStmt, BreakStmt, ContinueStmt, IfStmt, TryStmt, WithStmt, DelStmt,
ForStmt, BreakStmt, ContinueStmt, IfStmt, TryStmt, WithStmt, DelStmt, PassStmt,
GlobalDecl, SuperExpr, DictExpr, CallExpr, RefExpr, OpExpr, UnaryExpr,
SliceExpr, CastExpr, RevealTypeExpr, TypeApplication, Context, SymbolTable,
SymbolTableNode, BOUND_TVAR, UNBOUND_TVAR, ListComprehension, GeneratorExpr,
Expand All @@ -63,7 +63,7 @@
YieldFromExpr, NamedTupleExpr, NonlocalDecl, SymbolNode,
SetComprehension, DictionaryComprehension, TYPE_ALIAS, TypeAliasExpr,
YieldExpr, ExecStmt, Argument, BackquoteExpr, ImportBase, AwaitExpr,
IntExpr, FloatExpr, UnicodeExpr, EllipsisExpr,
IntExpr, FloatExpr, UnicodeExpr, EllipsisExpr, TempNode,
COVARIANT, CONTRAVARIANT, INVARIANT, UNBOUND_IMPORTED, LITERAL_YES,
)
from mypy.visitor import NodeVisitor
Expand Down Expand Up @@ -547,6 +547,8 @@ def check_function_signature(self, fdef: FuncItem) -> None:

def visit_class_def(self, defn: ClassDef) -> None:
self.clean_up_bases_and_infer_type_variables(defn)
if self.analyze_namedtuple_classdef(defn):
return
self.setup_class_def_analysis(defn)

self.bind_class_type_vars(defn)
Expand Down Expand Up @@ -724,6 +726,56 @@ def analyze_unbound_tvar(self, t: Type) -> Tuple[str, TypeVarExpr]:
return unbound.name, cast(TypeVarExpr, sym.node)
return None

def analyze_namedtuple_classdef(self, defn: ClassDef) -> bool:
# special case for NamedTuple
for base_expr in defn.base_type_exprs:
if isinstance(base_expr, RefExpr):
base_expr.accept(self)
if base_expr.fullname == 'typing.NamedTuple':
node = self.lookup(defn.name, defn)
if node is not None:
node.kind = GDEF # TODO in process_namedtuple_definition also applies here
items, types = self.check_namedtuple_classdef(defn)
node.node = self.build_namedtuple_typeinfo(defn.name, items, types)
return True
return False

def check_namedtuple_classdef(self, defn: ClassDef) -> Tuple[List[str], List[Type]]:
NAMEDTUP_CLASS_ERROR = ('Invalid statement in NamedTuple definition; '
'expected "field_name: field_type"')
if self.options.python_version < (3, 6):
self.fail('NamedTuple class syntax is only supported in Python 3.6', defn)
return [], []
if len(defn.base_type_exprs) > 1:
self.fail('NamedTuple should be a single base', defn)
items = [] # type: List[str]
types = [] # type: List[Type]
for stmt in defn.defs.body:
if not isinstance(stmt, AssignmentStmt):
# Still allow pass or ... (for empty namedtuples).
if (not isinstance(stmt, PassStmt) and
not (isinstance(stmt, ExpressionStmt) and
isinstance(stmt.expr, EllipsisExpr))):
self.fail(NAMEDTUP_CLASS_ERROR, stmt)
elif len(stmt.lvalues) > 1 or not isinstance(stmt.lvalues[0], NameExpr):
# An assignment, but an invalid one.
self.fail(NAMEDTUP_CLASS_ERROR, stmt)
else:
# Append name and type in this case...
name = stmt.lvalues[0].name
items.append(name)
types.append(AnyType() if stmt.type is None else self.anal_type(stmt.type))
# ...despite possible minor failures that allow further analyzis.
if name.startswith('_'):
self.fail('NamedTuple field name cannot start with an underscore: {}'
.format(name), stmt)
if stmt.type is None or hasattr(stmt, 'new_syntax') and not stmt.new_syntax:
self.fail(NAMEDTUP_CLASS_ERROR, stmt)
elif not isinstance(stmt.rvalue, TempNode):
# x: int assigns rvalue to TempNode(AnyType())
self.fail('Right hand side values are not supported in NamedTuple', stmt)
return items, types

def setup_class_def_analysis(self, defn: ClassDef) -> None:
"""Prepare for the analysis of a class definition."""
if not defn.info:
Expand Down
1 change: 1 addition & 0 deletions mypy/test/testcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
'check-warnings.test',
'check-async-await.test',
'check-newtype.test',
'check-class-namedtuple.test',
'check-columns.test',
]

Expand Down
Loading