diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index fee0957fc0d0..f1b8ebcaf54c 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -861,7 +861,7 @@ def visit_op_expr(self, e: OpExpr) -> Type: if e.op == '*' and isinstance(e.left, ListExpr): # Expressions of form [...] * e get special type inference. return self.check_list_multiply(e) - if e.op == '%' and isinstance(e.left, StrExpr): + if e.op == '%' and isinstance(e.left, (StrExpr, BytesExpr)): return self.strfrm_checker.check_str_interpolation(cast(StrExpr, e.left), e.right) left_type = self.accept(e.left) diff --git a/mypy/checkstrformat.py b/mypy/checkstrformat.py index 39e3fe468c7e..0b203e57faab 100644 --- a/mypy/checkstrformat.py +++ b/mypy/checkstrformat.py @@ -8,7 +8,7 @@ Type, AnyType, TupleType, Instance, UnionType ) from mypy.nodes import ( - Node, StrExpr, TupleExpr, DictExpr, Context + Node, StrExpr, BytesExpr, TupleExpr, DictExpr, Context ) if False: # break import cycle only needed for mypy @@ -136,7 +136,7 @@ def check_simple_str_interpolation(self, specifiers: List[ConversionSpecifier], def check_mapping_str_interpolation(self, specifiers: List[ConversionSpecifier], replacements: Node) -> None: dict_with_only_str_literal_keys = (isinstance(replacements, DictExpr) and - all(isinstance(k, StrExpr) + all(isinstance(k, (StrExpr, BytesExpr)) for k, v in cast(DictExpr, replacements).items)) if dict_with_only_str_literal_keys: mapping = {} # type: Dict[str, Type] @@ -255,7 +255,7 @@ def check_type(type: Type = None) -> None: def check_node(node: Node) -> None: """int, or str with length 1""" type = self.accept(node, expected_type) - if isinstance(node, StrExpr) and len(cast(StrExpr, node).value) != 1: + if isinstance(node, (StrExpr, BytesExpr)) and len(cast(StrExpr, node).value) != 1: self.msg.requires_int_or_char(context) check_type(type) diff --git a/mypy/exprtotype.py b/mypy/exprtotype.py index c01bc15377d0..dc95f3d4ba02 100644 --- a/mypy/exprtotype.py +++ b/mypy/exprtotype.py @@ -1,7 +1,7 @@ """Translate an expression (Node) to a Type value.""" from mypy.nodes import ( - Node, NameExpr, MemberExpr, IndexExpr, TupleExpr, ListExpr, StrExpr, EllipsisExpr + Node, NameExpr, MemberExpr, IndexExpr, TupleExpr, ListExpr, StrExpr, BytesExpr, EllipsisExpr ) from mypy.parsetype import parse_str_as_type, TypeParseError from mypy.types import Type, UnboundType, TypeList, EllipsisType @@ -42,7 +42,7 @@ def expr_to_unanalyzed_type(expr: Node) -> Type: elif isinstance(expr, ListExpr): return TypeList([expr_to_unanalyzed_type(t) for t in expr.items], line=expr.line) - elif isinstance(expr, StrExpr): + elif isinstance(expr, (StrExpr, BytesExpr)): # Parse string literal type. try: result = parse_str_as_type(expr.value, expr.line) diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 0719174d73f7..072807086742 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -1,15 +1,15 @@ from functools import wraps import sys -from typing import Tuple, Union, TypeVar, Callable, Sequence +from typing import Tuple, Union, TypeVar, Callable, Sequence, Optional, Any, cast, List from mypy.nodes import ( - MypyFile, Import, ImportAll, ImportFrom, FuncDef, OverloadedFuncDef, + MypyFile, Node, ImportBase, Import, ImportAll, ImportFrom, FuncDef, OverloadedFuncDef, ClassDef, Decorator, Block, Var, OperatorAssignmentStmt, ExpressionStmt, AssignmentStmt, ReturnStmt, RaiseStmt, AssertStmt, DelStmt, BreakStmt, ContinueStmt, PassStmt, GlobalDecl, WhileStmt, ForStmt, IfStmt, TryStmt, WithStmt, TupleExpr, GeneratorExpr, ListComprehension, ListExpr, ConditionalExpr, - DictExpr, SetExpr, NameExpr, IntExpr, StrExpr, BytesExpr, + DictExpr, SetExpr, NameExpr, IntExpr, StrExpr, BytesExpr, UnicodeExpr, FloatExpr, CallExpr, SuperExpr, MemberExpr, IndexExpr, SliceExpr, OpExpr, UnaryExpr, FuncExpr, ComparisonExpr, StarExpr, YieldFromExpr, NonlocalDecl, DictionaryComprehension, @@ -21,7 +21,9 @@ from mypy.errors import Errors try: - import typed_ast # type: ignore + from typed_ast import ast27 + from typed_ast import ast35 + from typed_ast import conversions except ImportError: print('You must install the typed_ast module before you can run mypy with `--fast-parser`.\n' 'The typed_ast module can be found at https://github.com/ddfisher/typed_ast', @@ -29,6 +31,7 @@ sys.exit(1) T = TypeVar('T') +U = TypeVar('U') def parse(source: Union[str, bytes], fnam: str = None, errors: Errors = None, @@ -43,7 +46,11 @@ def parse(source: Union[str, bytes], fnam: str = None, errors: Errors = None, """ is_stub_file = bool(fnam) and fnam.endswith('.pyi') try: - ast = typed_ast.parse(source, fnam, 'exec') + if pyversion[0] >= 3 or is_stub_file: + ast = ast35.parse(source, fnam, 'exec') + else: + ast2 = ast27.parse(source, fnam, 'exec') + ast = conversions.py2to3(ast2) except SyntaxError as e: if errors: errors.set_file('' if fnam is None else fnam) @@ -51,7 +58,9 @@ def parse(source: Union[str, bytes], fnam: str = None, errors: Errors = None, else: raise else: - tree = ASTConverter().visit(ast) + tree = ASTConverter(pyversion=pyversion, + custom_typing_module=custom_typing_module, + ).visit(ast) tree.path = fnam tree.is_stub = is_stub_file return tree @@ -64,11 +73,12 @@ def parse(source: Union[str, bytes], fnam: str = None, errors: Errors = None, def parse_type_comment(type_comment: str, line: int) -> Type: - typ = typed_ast.parse(type_comment, '', 'eval') + typ = ast35.parse(type_comment, '', 'eval') + assert isinstance(typ, ast35.Expression) return TypeConverter(line=line).visit(typ.body) -def with_line(f): +def with_line(f: Callable[[Any, T], U]) -> Callable[[Any, T], U]: @wraps(f) def wrapper(self, ast): node = f(self, ast) @@ -84,37 +94,40 @@ def find(f: Callable[[T], bool], seq: Sequence[T]) -> T: return None -class ASTConverter(typed_ast.NodeTransformer): - def __init__(self): - self.in_class = False - self.imports = [] +class ASTConverter(ast35.NodeTransformer): + def __init__(self, pyversion: Tuple[int, int], custom_typing_module: str = None) -> None: + self.class_nesting = 0 + self.imports = [] # type: List[ImportBase] + + self.pyversion = pyversion + self.custom_typing_module = custom_typing_module - def generic_visit(self, node): + def generic_visit(self, node: ast35.AST) -> None: raise RuntimeError('AST node not implemented: ' + str(type(node))) - def visit_NoneType(self, n): + def visit_NoneType(self, n: Any) -> Optional[Node]: return None - def visit_list(self, l): + def visit_list(self, l: Sequence[ast35.AST]) -> List[Node]: return [self.visit(e) for e in l] op_map = { - typed_ast.Add: '+', - typed_ast.Sub: '-', - typed_ast.Mult: '*', - typed_ast.MatMult: '@', - typed_ast.Div: '/', - typed_ast.Mod: '%', - typed_ast.Pow: '**', - typed_ast.LShift: '<<', - typed_ast.RShift: '>>', - typed_ast.BitOr: '|', - typed_ast.BitXor: '^', - typed_ast.BitAnd: '&', - typed_ast.FloorDiv: '//' + ast35.Add: '+', + ast35.Sub: '-', + ast35.Mult: '*', + ast35.MatMult: '@', + ast35.Div: '/', + ast35.Mod: '%', + ast35.Pow: '**', + ast35.LShift: '<<', + ast35.RShift: '>>', + ast35.BitOr: '|', + ast35.BitXor: '^', + ast35.BitAnd: '&', + ast35.FloorDiv: '//' } - def from_operator(self, op): + def from_operator(self, op: ast35.operator) -> str: op_name = ASTConverter.op_map.get(type(op)) if op_name is None: raise RuntimeError('Unknown operator ' + str(type(op))) @@ -124,34 +137,34 @@ def from_operator(self, op): return op_name comp_op_map = { - typed_ast.Gt: '>', - typed_ast.Lt: '<', - typed_ast.Eq: '==', - typed_ast.GtE: '>=', - typed_ast.LtE: '<=', - typed_ast.NotEq: '!=', - typed_ast.Is: 'is', - typed_ast.IsNot: 'is not', - typed_ast.In: 'in', - typed_ast.NotIn: 'not in' + ast35.Gt: '>', + ast35.Lt: '<', + ast35.Eq: '==', + ast35.GtE: '>=', + ast35.LtE: '<=', + ast35.NotEq: '!=', + ast35.Is: 'is', + ast35.IsNot: 'is not', + ast35.In: 'in', + ast35.NotIn: 'not in' } - def from_comp_operator(self, op): + def from_comp_operator(self, op: ast35.cmpop) -> str: op_name = ASTConverter.comp_op_map.get(type(op)) if op_name is None: raise RuntimeError('Unknown comparison operator ' + str(type(op))) else: return op_name - def as_block(self, stmts, lineno): + def as_block(self, stmts: List[ast35.stmt], lineno: int) -> Block: b = None if stmts: - b = Block(self.visit(stmts)) + b = Block(self.visit_list(stmts)) b.set_line(lineno) return b - def fix_function_overloads(self, stmts): - ret = [] + def fix_function_overloads(self, stmts: List[Node]) -> List[Node]: + ret = [] # type: List[Node] current_overload = [] current_overload_name = None # mypy doesn't actually check that the decorator is literally @overload @@ -178,8 +191,24 @@ def fix_function_overloads(self, stmts): ret.append(OverloadedFuncDef(current_overload)) return ret - def visit_Module(self, mod): - body = self.fix_function_overloads(self.visit(mod.body)) + def in_class(self) -> bool: + return self.class_nesting > 0 + + def translate_module_id(self, id: str) -> str: + """Return the actual, internal module id for a source text id. + + For example, translate '__builtin__' in Python 2 to 'builtins'. + """ + if id == self.custom_typing_module: + return 'typing' + elif id == '__builtin__' and self.pyversion[0] == 2: + # HACK: __builtin__ in Python 2 is aliases to builtins. However, the implementation + # is named __builtin__.py (there is another layer of translation elsewhere). + return 'builtins' + return id + + def visit_Module(self, mod: ast35.Module) -> Node: + body = self.fix_function_overloads(self.visit_list(mod.body)) return MypyFile(body, self.imports, @@ -193,19 +222,26 @@ def visit_Module(self, mod): # arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults, # arg? kwarg, expr* defaults) @with_line - def visit_FunctionDef(self, n): + def visit_FunctionDef(self, n: ast35.FunctionDef) -> Node: args = self.transform_args(n.args, n.lineno) arg_kinds = [arg.kind for arg in args] arg_names = [arg.variable.name() for arg in args] + arg_types = None # type: List[Type] if n.type_comment is not None: - func_type_ast = typed_ast.parse(n.type_comment, '', 'func_type') - arg_types = [a if a is not None else AnyType() for - a in TypeConverter(line=n.lineno).visit(func_type_ast.argtypes)] + func_type_ast = ast35.parse(n.type_comment, '', 'func_type') + assert isinstance(func_type_ast, ast35.FunctionType) + # for ellipsis arg + if (len(func_type_ast.argtypes) == 1 and + isinstance(func_type_ast.argtypes[0], ast35.Ellipsis)): + arg_types = [AnyType() for a in args] + else: + arg_types = [a if a is not None else AnyType() for + a in TypeConverter(line=n.lineno).visit_list(func_type_ast.argtypes)] return_type = TypeConverter(line=n.lineno).visit(func_type_ast.returns) # add implicit self type - if self.in_class and len(arg_types) < len(args): + if self.in_class() and len(arg_types) < len(args): arg_types.insert(0, AnyType()) else: arg_types = [a.type_annotation for a in args] @@ -234,11 +270,11 @@ def visit_FunctionDef(self, n): func_def.is_decorated = True func_def.set_line(n.lineno + len(n.decorator_list)) func_def.body.set_line(func_def.get_line()) - return Decorator(func_def, self.visit(n.decorator_list), var) + return Decorator(func_def, self.visit_list(n.decorator_list), var) else: return func_def - def transform_args(self, args, line): + def transform_args(self, args: ast35.arguments, line: int) -> List[Argument]: def make_argument(arg, default, kind): arg_type = TypeConverter(line=line).visit(arg.annotation) return Argument(Var(arg.arg), arg_type, self.visit(default), kind) @@ -275,10 +311,10 @@ def make_argument(arg, default, kind): # TODO: AsyncFunctionDef(identifier name, arguments args, # stmt* body, expr* decorator_list, expr? returns, string? type_comment) - def stringify_name(self, n): - if isinstance(n, typed_ast.Name): + def stringify_name(self, n: ast35.AST) -> str: + if isinstance(n, ast35.Name): return n.id - elif isinstance(n, typed_ast.Attribute): + elif isinstance(n, ast35.Attribute): return "{}.{}".format(self.stringify_name(n.value), n.attr) else: assert False, "can't stringify " + str(type(n)) @@ -289,32 +325,32 @@ def stringify_name(self, n): # stmt* body, # expr* decorator_list) @with_line - def visit_ClassDef(self, n): - self.in_class = True + def visit_ClassDef(self, n: ast35.ClassDef) -> Node: + self.class_nesting += 1 metaclass_arg = find(lambda x: x.arg == 'metaclass', n.keywords) metaclass = None if metaclass_arg: metaclass = self.stringify_name(metaclass_arg.value) cdef = ClassDef(n.name, - Block(self.fix_function_overloads(self.visit(n.body))), + Block(self.fix_function_overloads(self.visit_list(n.body))), None, - self.visit(n.bases), + self.visit_list(n.bases), metaclass=metaclass) - cdef.decorators = self.visit(n.decorator_list) - self.in_class = False + cdef.decorators = self.visit_list(n.decorator_list) + self.class_nesting -= 1 return cdef # Return(expr? value) @with_line - def visit_Return(self, n): + def visit_Return(self, n: ast35.Return) -> Node: return ReturnStmt(self.visit(n.value)) # Delete(expr* targets) @with_line - def visit_Delete(self, n): + def visit_Delete(self, n: ast35.Delete) -> Node: if len(n.targets) > 1: - tup = TupleExpr(self.visit(n.targets)) + tup = TupleExpr(self.visit_list(n.targets)) tup.set_line(n.lineno) return DelStmt(tup) else: @@ -322,25 +358,25 @@ def visit_Delete(self, n): # Assign(expr* targets, expr value, string? type_comment) @with_line - def visit_Assign(self, n): + def visit_Assign(self, n: ast35.Assign) -> Node: typ = None if n.type_comment: typ = parse_type_comment(n.type_comment, n.lineno) - return AssignmentStmt(self.visit(n.targets), + return AssignmentStmt(self.visit_list(n.targets), self.visit(n.value), type=typ) # AugAssign(expr target, operator op, expr value) @with_line - def visit_AugAssign(self, n): + def visit_AugAssign(self, n: ast35.AugAssign) -> Node: return OperatorAssignmentStmt(self.from_operator(n.op), self.visit(n.target), self.visit(n.value)) # For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment) @with_line - def visit_For(self, n): + def visit_For(self, n: ast35.For) -> Node: return ForStmt(self.visit(n.target), self.visit(n.iter), self.as_block(n.body, n.lineno), @@ -349,21 +385,21 @@ def visit_For(self, n): # TODO: AsyncFor(expr target, expr iter, stmt* body, stmt* orelse) # While(expr test, stmt* body, stmt* orelse) @with_line - def visit_While(self, n): + def visit_While(self, n: ast35.While) -> Node: return WhileStmt(self.visit(n.test), self.as_block(n.body, n.lineno), self.as_block(n.orelse, n.lineno)) # If(expr test, stmt* body, stmt* orelse) @with_line - def visit_If(self, n): + def visit_If(self, n: ast35.If) -> Node: return IfStmt([self.visit(n.test)], [self.as_block(n.body, n.lineno)], self.as_block(n.orelse, n.lineno)) # With(withitem* items, stmt* body, string? type_comment) @with_line - def visit_With(self, n): + def visit_With(self, n: ast35.With) -> Node: return WithStmt([self.visit(i.context_expr) for i in n.items], [self.visit(i.optional_vars) for i in n.items], self.as_block(n.body, n.lineno)) @@ -372,12 +408,12 @@ def visit_With(self, n): # Raise(expr? exc, expr? cause) @with_line - def visit_Raise(self, n): + def visit_Raise(self, n: ast35.Raise) -> Node: return RaiseStmt(self.visit(n.exc), self.visit(n.cause)) # Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody) @with_line - def visit_Try(self, n): + def visit_Try(self, n: ast35.Try) -> Node: vs = [NameExpr(h.name) if h.name is not None else None for h in n.handlers] types = [self.visit(h.type) for h in n.handlers] handlers = [self.as_block(h.body, h.lineno) for h in n.handlers] @@ -391,23 +427,24 @@ def visit_Try(self, n): # Assert(expr test, expr? msg) @with_line - def visit_Assert(self, n): + def visit_Assert(self, n: ast35.Assert) -> Node: return AssertStmt(self.visit(n.test)) # Import(alias* names) @with_line - def visit_Import(self, n): - i = Import([(a.name, a.asname) for a in n.names]) + def visit_Import(self, n: ast35.Import) -> Node: + i = Import([(self.translate_module_id(a.name), a.asname) for a in n.names]) self.imports.append(i) return i # ImportFrom(identifier? module, alias* names, int? level) @with_line - def visit_ImportFrom(self, n): + def visit_ImportFrom(self, n: ast35.ImportFrom) -> Node: + i = None # type: ImportBase if len(n.names) == 1 and n.names[0].name == '*': i = ImportAll(n.module, n.level) else: - i = ImportFrom(n.module if n.module is not None else '', + i = ImportFrom(self.translate_module_id(n.module) if n.module is not None else '', n.level, [(a.name, a.asname) for a in n.names]) self.imports.append(i) @@ -415,45 +452,45 @@ def visit_ImportFrom(self, n): # Global(identifier* names) @with_line - def visit_Global(self, n): + def visit_Global(self, n: ast35.Global) -> Node: return GlobalDecl(n.names) # Nonlocal(identifier* names) @with_line - def visit_Nonlocal(self, n): + def visit_Nonlocal(self, n: ast35.Nonlocal) -> Node: return NonlocalDecl(n.names) # Expr(expr value) @with_line - def visit_Expr(self, expr): - value = self.visit(expr.value) + def visit_Expr(self, n: ast35.Expr) -> Node: + value = self.visit(n.value) return ExpressionStmt(value) # Pass @with_line - def visit_Pass(self, n): + def visit_Pass(self, n: ast35.Pass) -> Node: return PassStmt() # Break @with_line - def visit_Break(self, n): + def visit_Break(self, n: ast35.Break) -> Node: return BreakStmt() # Continue @with_line - def visit_Continue(self, n): + def visit_Continue(self, n: ast35.Continue) -> Node: return ContinueStmt() # --- expr --- # BoolOp(boolop op, expr* values) @with_line - def visit_BoolOp(self, n): + def visit_BoolOp(self, n: ast35.BoolOp) -> Node: # mypy translates (1 and 2 and 3) as (1 and (2 and 3)) assert len(n.values) >= 2 op = None - if isinstance(n.op, typed_ast.And): + if isinstance(n.op, ast35.And): op = 'and' - elif isinstance(n.op, typed_ast.Or): + elif isinstance(n.op, ast35.Or): op = 'or' else: raise RuntimeError('unknown BoolOp ' + str(type(n))) @@ -465,11 +502,11 @@ def group(vals): else: return OpExpr(op, vals[0], group(vals[1:])) - return group(self.visit(n.values)) + return group(self.visit_list(n.values)) # BinOp(expr left, operator op, expr right) @with_line - def visit_BinOp(self, n): + def visit_BinOp(self, n: ast35.BinOp) -> Node: op = self.from_operator(n.op) if op is None: @@ -479,15 +516,15 @@ def visit_BinOp(self, n): # UnaryOp(unaryop op, expr operand) @with_line - def visit_UnaryOp(self, n): + def visit_UnaryOp(self, n: ast35.UnaryOp) -> Node: op = None - if isinstance(n.op, typed_ast.Invert): + if isinstance(n.op, ast35.Invert): op = '~' - elif isinstance(n.op, typed_ast.Not): + elif isinstance(n.op, ast35.Not): op = 'not' - elif isinstance(n.op, typed_ast.UAdd): + elif isinstance(n.op, ast35.UAdd): op = '+' - elif isinstance(n.op, typed_ast.USub): + elif isinstance(n.op, ast35.USub): op = '-' if op is None: @@ -497,8 +534,8 @@ def visit_UnaryOp(self, n): # Lambda(arguments args, expr body) @with_line - def visit_Lambda(self, n): - body = typed_ast.Return(n.body) + def visit_Lambda(self, n: ast35.Lambda) -> Node: + body = ast35.Return(n.body) body.lineno = n.lineno return FuncExpr(self.transform_args(n.args, n.lineno), @@ -506,37 +543,37 @@ def visit_Lambda(self, n): # IfExp(expr test, expr body, expr orelse) @with_line - def visit_IfExp(self, n): + def visit_IfExp(self, n: ast35.IfExp) -> Node: return ConditionalExpr(self.visit(n.test), self.visit(n.body), self.visit(n.orelse)) # Dict(expr* keys, expr* values) @with_line - def visit_Dict(self, n): - return DictExpr(list(zip(self.visit(n.keys), self.visit(n.values)))) + def visit_Dict(self, n: ast35.Dict) -> Node: + return DictExpr(list(zip(self.visit_list(n.keys), self.visit_list(n.values)))) # Set(expr* elts) @with_line - def visit_Set(self, n): - return SetExpr(self.visit(n.elts)) + def visit_Set(self, n: ast35.Set) -> Node: + return SetExpr(self.visit_list(n.elts)) # ListComp(expr elt, comprehension* generators) @with_line - def visit_ListComp(self, n): - return ListComprehension(self.visit_GeneratorExp(n)) + def visit_ListComp(self, n: ast35.ListComp) -> Node: + return ListComprehension(self.visit_GeneratorExp(cast(ast35.GeneratorExp, n))) # SetComp(expr elt, comprehension* generators) @with_line - def visit_SetComp(self, n): - return SetComprehension(self.visit_GeneratorExp(n)) + def visit_SetComp(self, n: ast35.SetComp) -> Node: + return SetComprehension(self.visit_GeneratorExp(cast(ast35.GeneratorExp, n))) # DictComp(expr key, expr value, comprehension* generators) @with_line - def visit_DictComp(self, n): + def visit_DictComp(self, n: ast35.DictComp) -> Node: targets = [self.visit(c.target) for c in n.generators] iters = [self.visit(c.iter) for c in n.generators] - ifs_list = [self.visit(c.ifs) for c in n.generators] + ifs_list = [self.visit_list(c.ifs) for c in n.generators] return DictionaryComprehension(self.visit(n.key), self.visit(n.value), targets, @@ -545,10 +582,10 @@ def visit_DictComp(self, n): # GeneratorExp(expr elt, comprehension* generators) @with_line - def visit_GeneratorExp(self, n): + def visit_GeneratorExp(self, n: ast35.GeneratorExp) -> GeneratorExpr: targets = [self.visit(c.target) for c in n.generators] iters = [self.visit(c.iter) for c in n.generators] - ifs_list = [self.visit(c.ifs) for c in n.generators] + ifs_list = [self.visit_list(c.ifs) for c in n.generators] return GeneratorExpr(self.visit(n.elt), targets, iters, @@ -558,77 +595,75 @@ def visit_GeneratorExp(self, n): # Yield(expr? value) @with_line - def visit_Yield(self, n): + def visit_Yield(self, n: ast35.Yield) -> Node: return YieldExpr(self.visit(n.value)) # YieldFrom(expr value) @with_line - def visit_YieldFrom(self, n): + def visit_YieldFrom(self, n: ast35.YieldFrom) -> Node: return YieldFromExpr(self.visit(n.value)) # Compare(expr left, cmpop* ops, expr* comparators) @with_line - def visit_Compare(self, n): + def visit_Compare(self, n: ast35.Compare) -> Node: operators = [self.from_comp_operator(o) for o in n.ops] - operands = self.visit([n.left] + n.comparators) + operands = self.visit_list([n.left] + n.comparators) return ComparisonExpr(operators, operands) # Call(expr func, expr* args, keyword* keywords) # keyword = (identifier? arg, expr value) @with_line - def visit_Call(self, n): - def is_stararg(a): - return isinstance(a, typed_ast.Starred) - + def visit_Call(self, n: ast35.Call) -> Node: def is_star2arg(k): return k.arg is None - arg_types = self.visit([a.value if is_stararg(a) else a for a in n.args] + - [k.value for k in n.keywords]) - arg_kinds = ([ARG_STAR if is_stararg(a) else ARG_POS for a in n.args] + + arg_types = self.visit_list( + [a.value if isinstance(a, ast35.Starred) else a for a in n.args] + + [k.value for k in n.keywords]) + arg_kinds = ([ARG_STAR if isinstance(a, ast35.Starred) else ARG_POS for a in n.args] + [ARG_STAR2 if is_star2arg(k) else ARG_NAMED for k in n.keywords]) return CallExpr(self.visit(n.func), arg_types, arg_kinds, - [None for _ in n.args] + [k.arg for k in n.keywords]) + cast("List[str]", [None for _ in n.args]) + [k.arg for k in n.keywords]) # Num(object n) -- a number as a PyObject. @with_line - def visit_Num(self, num): - if isinstance(num.n, int): - return IntExpr(num.n) - elif isinstance(num.n, float): - return FloatExpr(num.n) - elif isinstance(num.n, complex): - return ComplexExpr(num.n) + def visit_Num(self, n: ast35.Num) -> Node: + if isinstance(n.n, int): + return IntExpr(n.n) + elif isinstance(n.n, float): + return FloatExpr(n.n) + elif isinstance(n.n, complex): + return ComplexExpr(n.n) - raise RuntimeError('num not implemented for ' + str(type(num.n))) + raise RuntimeError('num not implemented for ' + str(type(n.n))) # Str(string s) -- need to specify raw, unicode, etc? @with_line - def visit_Str(self, n): + def visit_Str(self, n: ast35.Str) -> Node: return StrExpr(n.s) # Bytes(bytes s) @with_line - def visit_Bytes(self, n): + def visit_Bytes(self, n: ast35.Bytes) -> Node: # TODO: this is kind of hacky return BytesExpr(str(n.s)[2:-1]) # NameConstant(singleton value) - def visit_NameConstant(self, n): + def visit_NameConstant(self, n: ast35.NameConstant) -> Node: return NameExpr(str(n.value)) # Ellipsis @with_line - def visit_Ellipsis(self, n): + def visit_Ellipsis(self, n: ast35.Ellipsis) -> Node: return EllipsisExpr() # Attribute(expr value, identifier attr, expr_context ctx) @with_line - def visit_Attribute(self, n): - if (isinstance(n.value, typed_ast.Call) and - isinstance(n.value.func, typed_ast.Name) and + def visit_Attribute(self, n: ast35.Attribute) -> Node: + if (isinstance(n.value, ast35.Call) and + isinstance(n.value.func, ast35.Name) and n.value.func.id == 'super'): return SuperExpr(n.attr) @@ -636,90 +671,90 @@ def visit_Attribute(self, n): # Subscript(expr value, slice slice, expr_context ctx) @with_line - def visit_Subscript(self, n): + def visit_Subscript(self, n: ast35.Subscript) -> Node: return IndexExpr(self.visit(n.value), self.visit(n.slice)) # Starred(expr value, expr_context ctx) @with_line - def visit_Starred(self, n): + def visit_Starred(self, n: ast35.Starred) -> Node: return StarExpr(self.visit(n.value)) # Name(identifier id, expr_context ctx) @with_line - def visit_Name(self, n): + def visit_Name(self, n: ast35.Name) -> Node: return NameExpr(n.id) # List(expr* elts, expr_context ctx) @with_line - def visit_List(self, n): + def visit_List(self, n: ast35.List) -> Node: return ListExpr([self.visit(e) for e in n.elts]) # Tuple(expr* elts, expr_context ctx) @with_line - def visit_Tuple(self, n): + def visit_Tuple(self, n: ast35.Tuple) -> Node: return TupleExpr([self.visit(e) for e in n.elts]) # --- slice --- # Slice(expr? lower, expr? upper, expr? step) - def visit_Slice(self, n): + def visit_Slice(self, n: ast35.Slice) -> Node: return SliceExpr(self.visit(n.lower), self.visit(n.upper), self.visit(n.step)) # ExtSlice(slice* dims) - def visit_ExtSlice(self, n): - return TupleExpr(self.visit(n.dims)) + def visit_ExtSlice(self, n: ast35.ExtSlice) -> Node: + return TupleExpr(self.visit_list(n.dims)) # Index(expr value) - def visit_Index(self, n): + def visit_Index(self, n: ast35.Index) -> Node: return self.visit(n.value) -class TypeConverter(typed_ast.NodeTransformer): - def __init__(self, line=-1): +class TypeConverter(ast35.NodeTransformer): + def __init__(self, line: int = -1) -> None: self.line = line - def generic_visit(self, node): + def generic_visit(self, node: ast35.AST) -> None: raise RuntimeError('Type node not implemented: ' + str(type(node))) - def visit_NoneType(self, n): + def visit_NoneType(self, n: Any) -> Type: return None - def visit_list(self, l): + def visit_list(self, l: Sequence[ast35.AST]) -> List[Type]: return [self.visit(e) for e in l] - def visit_Name(self, n): + def visit_Name(self, n: ast35.Name) -> Type: return UnboundType(n.id, line=self.line) - def visit_NameConstant(self, n): + def visit_NameConstant(self, n: ast35.NameConstant) -> Type: return UnboundType(str(n.value)) # Str(string s) - def visit_Str(self, n): + def visit_Str(self, n: ast35.Str) -> Type: return parse_type_comment(n.s.strip(), line=self.line) # Subscript(expr value, slice slice, expr_context ctx) - def visit_Subscript(self, n): - assert isinstance(n.slice, typed_ast.Index) + def visit_Subscript(self, n: ast35.Subscript) -> Type: + assert isinstance(n.slice, ast35.Index) value = self.visit(n.value) assert isinstance(value, UnboundType) assert not value.args - if isinstance(n.slice.value, typed_ast.Tuple): - params = self.visit(n.slice.value.elts) + if isinstance(n.slice.value, ast35.Tuple): + params = self.visit_list(n.slice.value.elts) else: params = [self.visit(n.slice.value)] return UnboundType(value.name, params, line=self.line) - def visit_Tuple(self, n): - return TupleType(self.visit(n.elts), None, implicit=True, line=self.line) + def visit_Tuple(self, n: ast35.Tuple) -> Type: + return TupleType(self.visit_list(n.elts), None, implicit=True, line=self.line) # Attribute(expr value, identifier attr, expr_context ctx) - def visit_Attribute(self, n): + def visit_Attribute(self, n: ast35.Attribute) -> Type: before_dot = self.visit(n.value) assert isinstance(before_dot, UnboundType) @@ -728,9 +763,9 @@ def visit_Attribute(self, n): return UnboundType("{}.{}".format(before_dot.name, n.attr), line=self.line) # Ellipsis - def visit_Ellipsis(self, n): + def visit_Ellipsis(self, n: ast35.Ellipsis) -> Type: return EllipsisType(line=self.line) # List(expr* elts, expr_context ctx) - def visit_List(self, n): - return TypeList(self.visit(n.elts), line=self.line) + def visit_List(self, n: ast35.List) -> Type: + return TypeList(self.visit_list(n.elts), line=self.line) diff --git a/mypy/main.py b/mypy/main.py index 1cc3306f0893..40a279601bc8 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -199,10 +199,6 @@ def parse_version(v): parser.error('Python version 2 (or --py2) specified, ' 'but --use-python-path will search in sys.path of Python 3') - if args.fast_parser and args.python_version and args.python_version[0] == 2: - parser.error('The experimental fast parser is only compatible with Python 3, ' - 'but Python 2 specified.') - # Set options. options = Options() options.dirty_stubs = args.dirty_stubs diff --git a/mypy/semanal.py b/mypy/semanal.py index 3146643aa549..385d9d5edd73 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -58,7 +58,7 @@ SliceExpr, CastExpr, TypeApplication, Context, SymbolTable, SymbolTableNode, BOUND_TVAR, UNBOUND_TVAR, ListComprehension, GeneratorExpr, FuncExpr, MDEF, FuncBase, Decorator, SetExpr, TypeVarExpr, - StrExpr, PrintStmt, ConditionalExpr, PromoteExpr, + StrExpr, BytesExpr, PrintStmt, ConditionalExpr, PromoteExpr, ComparisonExpr, StarExpr, ARG_POS, ARG_NAMED, MroError, type_aliases, YieldFromExpr, NamedTupleExpr, NonlocalDecl, SetComprehension, DictionaryComprehension, TYPE_ALIAS, TypeAliasExpr, @@ -1279,7 +1279,7 @@ def check_typevar_name(self, call: CallExpr, name: str, context: Context) -> boo if len(call.args) < 1: self.fail("Too few arguments for TypeVar()", context) return False - if not isinstance(call.args[0], StrExpr) or not call.arg_kinds[0] == ARG_POS: + if not isinstance(call.args[0], (StrExpr, BytesExpr)) or not call.arg_kinds[0] == ARG_POS: self.fail("TypeVar() expects a string literal as first argument", context) return False if cast(StrExpr, call.args[0]).value != name: @@ -1425,13 +1425,13 @@ def parse_namedtuple_args(self, call: CallExpr, return self.fail_namedtuple_arg("Too many arguments for namedtuple()", call) if call.arg_kinds != [ARG_POS, ARG_POS]: return self.fail_namedtuple_arg("Unexpected arguments to namedtuple()", call) - if not isinstance(args[0], StrExpr): + if not isinstance(args[0], (StrExpr, BytesExpr)): return self.fail_namedtuple_arg( "namedtuple() expects a string literal as the first argument", call) types = [] # type: List[Type] ok = True if not isinstance(args[1], ListExpr): - if fullname == 'collections.namedtuple' and isinstance(args[1], StrExpr): + if fullname == 'collections.namedtuple' and isinstance(args[1], (StrExpr, BytesExpr)): str_expr = cast(StrExpr, args[1]) items = str_expr.value.split() else: @@ -1441,7 +1441,7 @@ def parse_namedtuple_args(self, call: CallExpr, listexpr = cast(ListExpr, args[1]) if fullname == 'collections.namedtuple': # The fields argument contains just names, with implicit Any types. - if any(not isinstance(item, StrExpr) for item in listexpr.items): + if any(not isinstance(item, (StrExpr, BytesExpr)) for item in listexpr.items): return self.fail_namedtuple_arg("String literal expected as namedtuple() item", call) items = [cast(StrExpr, item).value for item in listexpr.items] @@ -1462,7 +1462,7 @@ def parse_namedtuple_fields_with_types(self, nodes: List[Node], return self.fail_namedtuple_arg("Invalid NamedTuple field definition", item) name, type_node = item.items - if isinstance(name, StrExpr): + if isinstance(name, (StrExpr, BytesExpr)): items.append(name.value) else: return self.fail_namedtuple_arg("Invalid NamedTuple() field name", item)