Skip to content

Commit

Permalink
Tests all pass again after merge
Browse files Browse the repository at this point in the history
  • Loading branch information
sixolet committed Apr 18, 2017
1 parent 967bb5a commit bb5134e
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 63 deletions.
2 changes: 2 additions & 0 deletions mypy/exprtotype.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ def expr_to_unanalyzed_type(expr: Expression) -> Type:
types.append(expr_to_unanalyzed_type(it))
names.append(None)
kinds.append(ARG_POS)
def fail(message, Expression):
raise TypeTranslationError(message)
return ArgumentList(types, names, kinds,
line=expr.line, column=expr.column)
elif isinstance(expr, (StrExpr, BytesExpr, UnicodeExpr)):
Expand Down
29 changes: 17 additions & 12 deletions mypy/fastparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
StarExpr, YieldFromExpr, NonlocalDecl, DictionaryComprehension,
SetComprehension, ComplexExpr, EllipsisExpr, YieldExpr, Argument,
AwaitExpr, TempNode, Expression, Statement,
ARG_POS, ARG_OPT, ARG_STAR, ARG_NAMED, ARG_NAMED_OPT, ARG_STAR2
ARG_POS, ARG_OPT, ARG_STAR, ARG_NAMED, ARG_NAMED_OPT, ARG_STAR2,
check_arg_names,
)
from mypy.types import (
Type, CallableType, AnyType, UnboundType, TupleType, ArgumentList, EllipsisType,
Expand Down Expand Up @@ -152,6 +153,9 @@ def __init__(self,
def fail(self, msg: str, line: int, column: int) -> None:
self.errors.report(line, column, msg)

def fail_ast(self, msg: str, n: ast3.AST) -> None:
self.fail(msg, n.lineno, n.col_offset)

def generic_visit(self, node: ast3.AST) -> None:
raise RuntimeError('AST node not implemented: ' + str(type(node)))

Expand Down Expand Up @@ -445,13 +449,7 @@ def make_argument(arg: ast3.arg, default: Optional[ast3.expr], kind: int) -> Arg
new_args.append(make_argument(args.kwarg, None, ARG_STAR2))
names.append(args.kwarg)

seen_names = set() # type: Set[str]
for name in names:
if name.arg in seen_names:
self.fail("duplicate argument '{}' in function definition".format(name.arg),
name.lineno, name.col_offset)
break
seen_names.add(name.arg)
check_arg_names([name.arg for name in names], names, self.fail_ast)

return new_args

Expand Down Expand Up @@ -1010,7 +1008,7 @@ def translate_argument_list(self, l: Sequence[ast3.AST]) -> ArgumentList:
typ = AnyType(implicit=True) # type: Type
for i, arg in enumerate(e.args):
if i == 0 and not star:
name = _extract_str(arg)
name = self._extract_str(arg)
elif i == 1 and not star or i == 0 and star:
typ = self.visit(arg)
else:
Expand All @@ -1019,7 +1017,7 @@ def translate_argument_list(self, l: Sequence[ast3.AST]) -> ArgumentList:
for k in e.keywords:
value = k.value
if k.arg == "name" and not star:
name = _extract_str(value)
name = self._extract_str(value)
elif k.arg == "typ":
typ = self.visit(value)
else:
Expand All @@ -1037,6 +1035,14 @@ def translate_argument_list(self, l: Sequence[ast3.AST]) -> ArgumentList:

return ArgumentList(types, names, kinds, line=self.line)

def _extract_str(self, n: ast3.AST) -> str:
if isinstance(n, ast3.Str):
return n.s.strip()
elif isinstance(n, ast3.NameConstant) and str(n.value) == 'None':
return None
self.fail('Expected string literal for argument name, got "{}"'.format(n), n.lineno, n.col_offset)
return None

def visit_Name(self, n: ast3.Name) -> Type:
return UnboundType(n.id, line=self.line)

Expand Down Expand Up @@ -1089,5 +1095,4 @@ def visit_Ellipsis(self, n: ast3.Ellipsis) -> Type:
# List(expr* elts, expr_context ctx)
def visit_List(self, n: ast3.List) -> Type:
l = len(n.elts)
return ArgumentList(
self.translate_expr_list(n.elts), [None]*l, [ARG_POS]*l, line=self.line)
return self.translate_argument_list(n.elts)
42 changes: 41 additions & 1 deletion mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from abc import abstractmethod

from typing import (
Any, TypeVar, List, Tuple, cast, Set, Dict, Union, Optional
Any, TypeVar, List, Tuple, cast, Set, Dict, Union, Optional, Callable,
)

import mypy.strconv
Expand Down Expand Up @@ -2447,3 +2447,43 @@ def get_member_expr_fullname(expr: MemberExpr) -> str:
for key, obj in globals().items()
if isinstance(obj, type) and issubclass(obj, SymbolNode) and obj is not SymbolNode
}

def check_arg_kinds(arg_kinds: List[int], nodes: List[T], fail: Callable[[str, T], None]) -> None:
is_var_arg = False
is_kw_arg = False
seen_named = False
seen_opt = False
for kind, node in zip(arg_kinds, nodes):
if kind == ARG_POS:
if is_var_arg or is_kw_arg or seen_named or seen_opt:
fail("Required positional args may not appear "
"after default, named or star args",
node)
break
elif kind == ARG_OPT:
if is_var_arg or is_kw_arg or seen_named:
fail("Positional default args may not appear after named or star args", node)
break
seen_opt = True
elif kind == ARG_STAR:
if is_var_arg or is_kw_arg or seen_named:
fail("Star args may not appear after named or star args", node)
break
is_var_arg = True
elif kind == ARG_NAMED or kind == ARG_NAMED_OPT:
seen_named = True
elif kind == ARG_STAR2:
if is_kw_arg:
fail("You may only have one **kwargs argument", node)
break
is_kw_arg = True


def check_arg_names(names: List[str], nodes: List[T], fail: Callable[[str, T], None],
description: str = 'function definition') -> None:
seen_names = set() # type: Set[str]
for name, node in zip(names, nodes):
if name is not None and name in seen_names:
fail("duplicate argument '{}' in {}".format(name, description), node)
break
seen_names.add(name)
4 changes: 2 additions & 2 deletions mypy/server/astdiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from mypy.nodes import SymbolTable, SymbolTableNode, FuncBase, TypeInfo, Var
from mypy.types import (
Type, TypeVisitor, UnboundType, TypeList, AnyType, NoneTyp, UninhabitedType,
Type, TypeVisitor, UnboundType, ArgumentList, AnyType, NoneTyp, UninhabitedType,
ErasedType, DeletedType, Instance, TypeVarType, CallableType, TupleType, TypedDictType,
UnionType, Overloaded, PartialType, TypeType
)
Expand Down Expand Up @@ -137,7 +137,7 @@ def __init__(self, right: Type) -> None:
def visit_unbound_type(self, left: UnboundType) -> bool:
return False

def visit_type_list(self, t: TypeList) -> bool:
def visit_type_list(self, t: ArgumentList) -> bool:
assert False, 'Not supported'

def visit_any(self, left: AnyType) -> bool:
Expand Down
5 changes: 4 additions & 1 deletion mypy/typeanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
StarType, PartialType, EllipsisType, UninhabitedType, TypeType, get_typ_args, set_typ_args,
ArgKindException, ArgNameException, get_type_vars, union_items
)

from mypy.nodes import (
BOUND_TVAR, UNBOUND_TVAR, TYPE_ALIAS, UNBOUND_IMPORTED,
TypeInfo, Context, SymbolTableNode, Var, Expression,
IndexExpr, RefExpr, nongen_builtins,
IndexExpr, RefExpr, nongen_builtins, check_arg_names, check_arg_kinds,
)
from mypy.sametypes import is_same_type
from mypy.exprtotype import expr_to_unanalyzed_type, TypeTranslationError
Expand Down Expand Up @@ -382,6 +383,8 @@ def analyze_callable_type(self, t: UnboundType) -> Type:
# Callable[[ARG, ...], RET] (ordinary callable type)
args = t.args[0].types
try:
check_arg_names(t.args[0].names, [t]*len(args), self.fail, "Callable")
check_arg_kinds(t.args[0].kinds, [t]*len(args), self.fail)
return CallableType(self.anal_array(args),
t.args[0].kinds,
t.args[0].names,
Expand Down
39 changes: 2 additions & 37 deletions mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,13 +585,13 @@ def __init__(self,
special_sig: Optional[str] = None,
from_type_type: bool = False,
) -> None:
self._process_kinds_on_init(arg_kinds)
self._process_names_on_init(arg_names)
if variables is None:
variables = []
assert len(arg_types) == len(arg_kinds)
self.arg_types = arg_types
self.arg_kinds = arg_kinds
self.is_var_arg = ARG_STAR in arg_kinds
self.is_kw_arg = ARG_STAR2 in arg_kinds
self.arg_names = arg_names
self.min_args = arg_kinds.count(ARG_POS)
self.ret_type = ret_type
Expand All @@ -607,41 +607,6 @@ def __init__(self,
self.from_type_type = from_type_type
super().__init__(line, column)

def _process_names_on_init(self, arg_names):
seen = set() # type: Set[str]
for name in arg_names:
if name is None:
continue
if name in seen:
raise ArgNameException('Duplicate argument name "{}"'.format(name))
seen.add(name)

def _process_kinds_on_init(self, arg_kinds):
self.is_var_arg = False
self.is_kw_arg = False
seen_named = False
seen_opt = False
for kind in arg_kinds:
if kind == ARG_POS:
if self.is_var_arg or self.is_kw_arg or seen_named or seen_opt:
raise ArgKindException("Required positional args may not appear "
"after default, named or star args")
elif kind == ARG_OPT:
if self.is_var_arg or self.is_kw_arg or seen_named:
raise ArgKindException("Positional default args may not appear "
"after named or star args")
seen_opt = True
elif kind == ARG_STAR:
if self.is_var_arg or self.is_kw_arg or seen_named:
raise ArgKindException("Star args may not appear after named or star args")
self.is_var_arg = True
elif kind == ARG_NAMED or kind == ARG_NAMED_OPT:
seen_named = True
elif kind == ARG_STAR2:
if self.is_kw_arg:
raise ArgKindException("You may only have one **kwargs argument")
self.is_kw_arg = True

def copy_modified(self,
arg_types: List[Type] = _dummy,
arg_kinds: List[int] = _dummy,
Expand Down
16 changes: 6 additions & 10 deletions test-data/unit/check-functions.test
Original file line number Diff line number Diff line change
Expand Up @@ -1474,13 +1474,13 @@ from mypy_extensions import Arg, StarArg, KwArg

def WrongArg(x, y): return y

def a(f: Callable[[WrongArg('x', int)], int]): pass # E: Parse error before (: Unknown argument constructor WrongArg # E: Parse error before end of line
def b(f: Callable[[Arg('x', 1)], int]): pass # E: Parse error before numeric literal # E: Parse error before end of line
def c(f: Callable[[StarArg('x', int)], int]): pass # E: Parse error before "int": Unexpected argument for argument constructor # E: Parse error before end of line
def a(f: Callable[[WrongArg('x', int)], int]): pass # E: Unknown argument constructor WrongArg
def b(f: Callable[[Arg('x', 1)], int]): pass # E: invalid type comment or annotation
def c(f: Callable[[StarArg('x', int)], int]): pass # E: Too many arguments for argument constructor
def d(f: Callable[[StarArg(int)], int]): pass # ok
def e(f: Callable[[StarArg(), KwArg()], int]): pass # ok
def g(f: Callable[[Arg(name='x', typ=int)], int]): pass # ok
def h(f: Callable[[Arg(gnome='x', typ=int)], int]): pass # E: Parse error before "gnome": Unexpected argument "gnome" for argument constructor # E: Parse error before end of line
def h(f: Callable[[Arg(gnome='x', typ=int)], int]): pass # E: Unexpected argument "gnome" for argument constructor
def i(f: Callable[[Arg(name=None, typ=int)], int]): pass # ok

[builtins fixtures/dict.pyi]
Expand All @@ -1493,21 +1493,18 @@ def a(f: Callable[[WrongArg('x', int)], int]): pass # E: Unknown argument constr
[builtins fixtures/dict.pyi]

[case testCallableFastParseWrongTypeType]
# flags: --fast-parser
from typing import Callable
from mypy_extensions import Arg
def b(f: Callable[[Arg('x', 1)], int]): pass # E: Bad type for callable argument
def b(f: Callable[[Arg('x', 1)], int]): pass # E: invalid type comment or annotation
[builtins fixtures/dict.pyi]

[case testCallableFastParseTooManyStarArg]
# flags: --fast-parser
from typing import Callable
from mypy_extensions import StarArg
def c(f: Callable[[StarArg('x', int)], int]): pass # E: Too many arguments for argument constructor
[builtins fixtures/dict.pyi]

[case testCallableFastParseGood]
# flags: --fast-parser
from typing import Callable
from mypy_extensions import StarArg, Arg
def d(f: Callable[[StarArg(int)], int]): pass # ok
Expand All @@ -1517,7 +1514,6 @@ def i(f: Callable[[Arg(name=None, typ=int)], int]): pass # ok
[builtins fixtures/dict.pyi]

[case testCallableFastParseBadArgArgName]
# flags: --fast-parser
from typing import Callable
from mypy_extensions import Arg
def h(f: Callable[[Arg(gnome='x', typ=int)], int]): pass # E: Unexpected argument "gnome" for argument constructor
Expand All @@ -1539,7 +1535,7 @@ def j(f: Callable[[NamedArg('x'), DefaultArg('y', int)], int]): pass # E: Positi
from typing import Callable
from mypy_extensions import Arg, StarArg, KwArg, DefaultArg

def f(f: Callable[[Arg('x', int), int, Arg('x', int)], int]): pass # E: Duplicate argument name "x"
def f(f: Callable[[Arg('x', int), int, Arg('x', int)], int]): pass # E: duplicate argument 'x' in Callable

[builtins fixtures/dict.pyi]

Expand Down

0 comments on commit bb5134e

Please sign in to comment.