1
+ import re
1
2
import sys
2
3
3
4
from typing import (
@@ -120,6 +121,8 @@ def ast3_parse(source: Union[str, bytes], filename: str, mode: str,
120
121
121
122
TYPE_COMMENT_SYNTAX_ERROR = 'syntax error in type comment' # type: Final
122
123
124
+ TYPE_IGNORE_PATTERN = re .compile (r'[^#]*#\s*type:\s*ignore\s*($|#)' )
125
+
123
126
124
127
# Older versions of typing don't allow using overload outside stubs,
125
128
# so provide a dummy.
@@ -180,18 +183,19 @@ def parse_type_comment(type_comment: str,
180
183
line : int ,
181
184
errors : Optional [Errors ],
182
185
assume_str_is_unicode : bool = True ,
183
- ) -> Optional [Type ]:
186
+ ) -> Tuple [ bool , Optional [Type ] ]:
184
187
try :
185
188
typ = ast3_parse (type_comment , '<type_comment>' , 'eval' )
186
189
except SyntaxError as e :
187
190
if errors is not None :
188
191
errors .report (line , e .offset , TYPE_COMMENT_SYNTAX_ERROR , blocker = True )
189
- return None
192
+ return False , None
190
193
else :
191
194
raise
192
195
else :
196
+ extra_ignore = TYPE_IGNORE_PATTERN .match (type_comment ) is not None
193
197
assert isinstance (typ , ast3_Expression )
194
- return TypeConverter (errors , line = line ,
198
+ return extra_ignore , TypeConverter (errors , line = line ,
195
199
assume_str_is_unicode = assume_str_is_unicode ).visit (typ .body )
196
200
197
201
@@ -212,8 +216,8 @@ def parse_type_string(expr_string: str, expr_fallback_name: str,
212
216
code with unicode_literals...) and setting `assume_str_is_unicode` accordingly.
213
217
"""
214
218
try :
215
- node = parse_type_comment (expr_string .strip (), line = line , errors = None ,
216
- assume_str_is_unicode = assume_str_is_unicode )
219
+ _ , node = parse_type_comment (expr_string .strip (), line = line , errors = None ,
220
+ assume_str_is_unicode = assume_str_is_unicode )
217
221
if isinstance (node , UnboundType ) and node .original_str_expr is None :
218
222
node .original_str_expr = expr_string
219
223
node .original_str_fallback = expr_fallback_name
@@ -247,6 +251,8 @@ def __init__(self,
247
251
self .is_stub = is_stub
248
252
self .errors = errors
249
253
254
+ self .extra_type_ignores = [] # type: List[int]
255
+
250
256
# Cache of visit_X methods keyed by type of visited object
251
257
self .visitor_cache = {} # type: Dict[type, Callable[[Optional[AST]], Any]]
252
258
@@ -389,11 +395,12 @@ def translate_module_id(self, id: str) -> str:
389
395
390
396
def visit_Module (self , mod : ast3 .Module ) -> MypyFile :
391
397
body = self .fix_function_overloads (self .translate_stmt_list (mod .body ))
392
-
398
+ ignores = [ti .lineno for ti in mod .type_ignores ]
399
+ ignores .extend (self .extra_type_ignores )
393
400
return MypyFile (body ,
394
401
self .imports ,
395
402
False ,
396
- {ti . lineno for ti in mod . type_ignores },
403
+ {* ignores },
397
404
)
398
405
399
406
# --- stmt ---
@@ -587,7 +594,10 @@ def make_argument(self, arg: ast3.arg, default: Optional[ast3.expr], kind: int,
587
594
if annotation is not None :
588
595
arg_type = TypeConverter (self .errors , line = arg .lineno ).visit (annotation )
589
596
elif type_comment is not None :
590
- arg_type = parse_type_comment (type_comment , arg .lineno , self .errors )
597
+ extra_ignore , arg_type = parse_type_comment (type_comment , arg .lineno , self .errors )
598
+ if extra_ignore :
599
+ self .extra_type_ignores .append (arg .lineno )
600
+
591
601
return Argument (Var (arg .arg ), arg_type , self .visit (default ), kind )
592
602
593
603
def fail_arg (self , msg : str , arg : ast3 .arg ) -> None :
@@ -642,7 +652,9 @@ def visit_Assign(self, n: ast3.Assign) -> AssignmentStmt:
642
652
lvalues = self .translate_expr_list (n .targets )
643
653
rvalue = self .visit (n .value )
644
654
if n .type_comment is not None :
645
- typ = parse_type_comment (n .type_comment , n .lineno , self .errors )
655
+ extra_ignore , typ = parse_type_comment (n .type_comment , n .lineno , self .errors )
656
+ if extra_ignore :
657
+ self .extra_type_ignores .append (n .lineno )
646
658
else :
647
659
typ = None
648
660
s = AssignmentStmt (lvalues , rvalue , type = typ , new_syntax = False )
@@ -674,7 +686,9 @@ def visit_NamedExpr(self, n: NamedExpr) -> None:
674
686
# For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
675
687
def visit_For (self , n : ast3 .For ) -> ForStmt :
676
688
if n .type_comment is not None :
677
- target_type = parse_type_comment (n .type_comment , n .lineno , self .errors )
689
+ extra_ignore , target_type = parse_type_comment (n .type_comment , n .lineno , self .errors )
690
+ if extra_ignore :
691
+ self .extra_type_ignores .append (n .lineno )
678
692
else :
679
693
target_type = None
680
694
node = ForStmt (self .visit (n .target ),
@@ -687,7 +701,9 @@ def visit_For(self, n: ast3.For) -> ForStmt:
687
701
# AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
688
702
def visit_AsyncFor (self , n : ast3 .AsyncFor ) -> ForStmt :
689
703
if n .type_comment is not None :
690
- target_type = parse_type_comment (n .type_comment , n .lineno , self .errors )
704
+ extra_ignore , target_type = parse_type_comment (n .type_comment , n .lineno , self .errors )
705
+ if extra_ignore :
706
+ self .extra_type_ignores .append (n .lineno )
691
707
else :
692
708
target_type = None
693
709
node = ForStmt (self .visit (n .target ),
@@ -716,7 +732,9 @@ def visit_If(self, n: ast3.If) -> IfStmt:
716
732
# With(withitem* items, stmt* body, string? type_comment)
717
733
def visit_With (self , n : ast3 .With ) -> WithStmt :
718
734
if n .type_comment is not None :
719
- target_type = parse_type_comment (n .type_comment , n .lineno , self .errors )
735
+ extra_ignore , target_type = parse_type_comment (n .type_comment , n .lineno , self .errors )
736
+ if extra_ignore :
737
+ self .extra_type_ignores .append (n .lineno )
720
738
else :
721
739
target_type = None
722
740
node = WithStmt ([self .visit (i .context_expr ) for i in n .items ],
@@ -728,7 +746,9 @@ def visit_With(self, n: ast3.With) -> WithStmt:
728
746
# AsyncWith(withitem* items, stmt* body, string? type_comment)
729
747
def visit_AsyncWith (self , n : ast3 .AsyncWith ) -> WithStmt :
730
748
if n .type_comment is not None :
731
- target_type = parse_type_comment (n .type_comment , n .lineno , self .errors )
749
+ extra_ignore , target_type = parse_type_comment (n .type_comment , n .lineno , self .errors )
750
+ if extra_ignore :
751
+ self .extra_type_ignores .append (n .lineno )
732
752
else :
733
753
target_type = None
734
754
s = WithStmt ([self .visit (i .context_expr ) for i in n .items ],
@@ -1211,11 +1231,11 @@ def visit_raw_str(self, s: str) -> Type:
1211
1231
# An escape hatch that allows the AST walker in fastparse2 to
1212
1232
# directly hook into the Python 3.5 type converter in some cases
1213
1233
# without needing to create an intermediary `Str` object.
1214
- return ( parse_type_comment (s .strip (),
1215
- self .line ,
1216
- self .errors ,
1217
- self .assume_str_is_unicode )
1218
- or AnyType (TypeOfAny .from_error ) )
1234
+ _ , typ = parse_type_comment (s .strip (),
1235
+ self .line ,
1236
+ self .errors ,
1237
+ self .assume_str_is_unicode )
1238
+ return typ or AnyType (TypeOfAny .from_error )
1219
1239
1220
1240
def visit_Call (self , e : Call ) -> Type :
1221
1241
# Parse the arg constructor
0 commit comments