Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
249d70f
Implement Callable[[Arg('name', Type)], ret] syntax
sixolet Nov 11, 2016
7ecdcc1
General cleanup
sixolet Dec 24, 2016
066bd5e
Change tests back to match old behavior
sixolet Dec 24, 2016
213944b
lots of lint
sixolet Dec 24, 2016
0e19070
Oh god I am tired of writing parsers
sixolet Dec 25, 2016
3f2f617
Tighten fastparse a little
sixolet Dec 25, 2016
0b69630
make all tests pass now
sixolet Dec 25, 2016
f4ccf92
go back to master version of typeshed I guess
sixolet Dec 25, 2016
967bb5a
Meged master, but tests fail again now.
sixolet Apr 12, 2017
bb5134e
Tests all pass again after merge
sixolet Apr 18, 2017
d4a83e1
Merged master again
sixolet Apr 18, 2017
54a5da9
Big refactor. Wait until semanal to get arg kinds, switch order again…
sixolet Apr 20, 2017
e79c527
Change back to TypeList
sixolet Apr 20, 2017
52ffe5c
Cleanups. Preparing to split into two diffs maybe?
sixolet Apr 20, 2017
06416f7
update typeshed to master version
sixolet Apr 20, 2017
398fbad
more cleanups
sixolet Apr 20, 2017
2c9ce02
should not have changed these test files
sixolet Apr 20, 2017
51c6f56
Semanal needs to be a SyntheticTypeVisitor
sixolet Apr 20, 2017
5e679a3
Annot
sixolet Apr 20, 2017
0926fe9
Oops
sixolet Apr 20, 2017
288a8be
Add testing for exprtotype Arg constructors in wierd places
sixolet Apr 20, 2017
6e67ab2
Remove some ill-modified modifications to tests
sixolet Apr 20, 2017
97a859b
Merge master, no longer depend on other PR
sixolet Apr 20, 2017
1c7d4c6
Jukka comments
sixolet Apr 21, 2017
f153850
Synthetic types don't serialize
sixolet Apr 21, 2017
be954f5
Remove unused instance var
sixolet Apr 21, 2017
07ae917
Merge master
sixolet Apr 22, 2017
1b97362
Revert "Remove unused instance var"
sixolet Apr 22, 2017
552f49e
Accessing TypeList types directly is not required
sixolet Apr 22, 2017
f2e3663
Undo changes to this file they were not required
sixolet Apr 22, 2017
27e2a9d
lint
sixolet Apr 22, 2017
793a663
Merge master again
sixolet Apr 22, 2017
3d212b3
Merge master
sixolet May 1, 2017
0780149
Disallow CallableArgument in exprtotype outside a TypeList
sixolet May 1, 2017
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
Prev Previous commit
Next Next commit
Tests all pass again after merge
  • Loading branch information
sixolet committed Apr 18, 2017
commit bb5134efda9f588c3217b6eab70c0870f00852e7
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:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change messaging to refer to "var args"

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:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we shouldn't allow these after **kwargs, since Python doesn't seem to allow anything after **kwargs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

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)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capitalize.

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