19
19
StarExpr , YieldFromExpr , NonlocalDecl , DictionaryComprehension ,
20
20
SetComprehension , ComplexExpr , EllipsisExpr , YieldExpr , Argument ,
21
21
AwaitExpr , TempNode , Expression , Statement ,
22
- ARG_POS , ARG_OPT , ARG_STAR , ARG_NAMED , ARG_NAMED_OPT , ARG_STAR2
22
+ ARG_POS , ARG_OPT , ARG_STAR , ARG_NAMED , ARG_NAMED_OPT , ARG_STAR2 ,
23
+ check_arg_names ,
23
24
)
24
25
from mypy .types import (
25
26
Type , CallableType , AnyType , UnboundType , TupleType , TypeList , EllipsisType ,
27
+ CallableArgument ,
26
28
)
27
29
from mypy import defaults
28
30
from mypy import experiments
@@ -444,24 +446,12 @@ def make_argument(arg: ast3.arg, default: Optional[ast3.expr], kind: int) -> Arg
444
446
new_args .append (make_argument (args .kwarg , None , ARG_STAR2 ))
445
447
names .append (args .kwarg )
446
448
447
- seen_names = set () # type: Set[str]
448
- for name in names :
449
- if name .arg in seen_names :
450
- self .fail ("duplicate argument '{}' in function definition" .format (name .arg ),
451
- name .lineno , name .col_offset )
452
- break
453
- seen_names .add (name .arg )
449
+ def fail_arg (msg : str , arg : ast3 .arg ) -> None :
450
+ self .fail (msg , arg .lineno , arg .col_offset )
454
451
455
- return new_args
452
+ check_arg_names ([ name . arg for name in names ], names , fail_arg )
456
453
457
- def stringify_name (self , n : ast3 .AST ) -> str :
458
- if isinstance (n , ast3 .Name ):
459
- return n .id
460
- elif isinstance (n , ast3 .Attribute ):
461
- sv = self .stringify_name (n .value )
462
- if sv is not None :
463
- return "{}.{}" .format (sv , n .attr )
464
- return None # Can't do it.
454
+ return new_args
465
455
466
456
# ClassDef(identifier name,
467
457
# expr* bases,
@@ -474,7 +464,7 @@ def visit_ClassDef(self, n: ast3.ClassDef) -> ClassDef:
474
464
metaclass_arg = find (lambda x : x .arg == 'metaclass' , n .keywords )
475
465
metaclass = None
476
466
if metaclass_arg :
477
- metaclass = self . stringify_name (metaclass_arg .value )
467
+ metaclass = stringify_name (metaclass_arg .value )
478
468
if metaclass is None :
479
469
metaclass = '<error>' # To be reported later
480
470
@@ -965,6 +955,21 @@ class TypeConverter(ast3.NodeTransformer): # type: ignore # typeshed PR #931
965
955
def __init__ (self , errors : Errors , line : int = - 1 ) -> None :
966
956
self .errors = errors
967
957
self .line = line
958
+ self .node_stack = [] # type: List[ast3.AST]
959
+
960
+ def visit (self , node : ast3 .AST ) -> Type :
961
+ """Modified visit -- keep track of the stack of nodes"""
962
+ self .node_stack .append (node )
963
+ try :
964
+ return super ().visit (node )
965
+ finally :
966
+ self .node_stack .pop ()
967
+
968
+ def parent (self ) -> ast3 .AST :
969
+ """Return the AST node above the one we are processing"""
970
+ if len (self .node_stack ) < 2 :
971
+ return None
972
+ return self .node_stack [- 2 ]
968
973
969
974
def fail (self , msg : str , line : int , column : int ) -> None :
970
975
self .errors .report (line , column , msg )
@@ -985,6 +990,55 @@ def visit_NoneType(self, n: Any) -> Type:
985
990
def translate_expr_list (self , l : Sequence [ast3 .AST ]) -> List [Type ]:
986
991
return [self .visit (e ) for e in l ]
987
992
993
+ def visit_Call (self , e : ast3 .Call ) -> Type :
994
+ # Parse the arg constructor
995
+ if not isinstance (self .parent (), ast3 .List ):
996
+ return self .generic_visit (e )
997
+ f = e .func
998
+ constructor = stringify_name (f )
999
+ if not constructor :
1000
+ self .fail ("Expected arg constructor name" , e .lineno , e .col_offset )
1001
+ name = None # type: Optional[str]
1002
+ default_type = AnyType (implicit = True )
1003
+ typ = default_type # type: Type
1004
+ for i , arg in enumerate (e .args ):
1005
+ if i == 0 :
1006
+ typ = self .visit (arg )
1007
+ elif i == 1 :
1008
+ name = self ._extract_argument_name (arg )
1009
+ else :
1010
+ self .fail ("Too many arguments for argument constructor" ,
1011
+ f .lineno , f .col_offset )
1012
+ for k in e .keywords :
1013
+ value = k .value
1014
+ if k .arg == "name" :
1015
+ if name is not None :
1016
+ self .fail ('"{}" gets multiple values for keyword argument "name"' .format (
1017
+ constructor ), f .lineno , f .col_offset )
1018
+ name = self ._extract_argument_name (value )
1019
+ elif k .arg == "type" :
1020
+ if typ is not default_type :
1021
+ self .fail ('"{}" gets multiple values for keyword argument "type"' .format (
1022
+ constructor ), f .lineno , f .col_offset )
1023
+ typ = self .visit (value )
1024
+ else :
1025
+ self .fail (
1026
+ 'Unexpected argument "{}" for argument constructor' .format (k .arg ),
1027
+ value .lineno , value .col_offset )
1028
+ return CallableArgument (typ , name , constructor , e .lineno , e .col_offset )
1029
+
1030
+ def translate_argument_list (self , l : Sequence [ast3 .AST ]) -> TypeList :
1031
+ return TypeList ([self .visit (e ) for e in l ], line = self .line )
1032
+
1033
+ def _extract_argument_name (self , n : ast3 .expr ) -> str :
1034
+ if isinstance (n , ast3 .Str ):
1035
+ return n .s .strip ()
1036
+ elif isinstance (n , ast3 .NameConstant ) and str (n .value ) == 'None' :
1037
+ return None
1038
+ self .fail ('Expected string literal for argument name, got {}' .format (
1039
+ type (n ).__name__ ), self .line , 0 )
1040
+ return None
1041
+
988
1042
def visit_Name (self , n : ast3 .Name ) -> Type :
989
1043
return UnboundType (n .id , line = self .line )
990
1044
@@ -1036,4 +1090,14 @@ def visit_Ellipsis(self, n: ast3.Ellipsis) -> Type:
1036
1090
1037
1091
# List(expr* elts, expr_context ctx)
1038
1092
def visit_List (self , n : ast3 .List ) -> Type :
1039
- return TypeList (self .translate_expr_list (n .elts ), line = self .line )
1093
+ return self .translate_argument_list (n .elts )
1094
+
1095
+
1096
+ def stringify_name (n : ast3 .AST ) -> Optional [str ]:
1097
+ if isinstance (n , ast3 .Name ):
1098
+ return n .id
1099
+ elif isinstance (n , ast3 .Attribute ):
1100
+ sv = stringify_name (n .value )
1101
+ if sv is not None :
1102
+ return "{}.{}" .format (sv , n .attr )
1103
+ return None # Can't do it.
0 commit comments