@@ -41,6 +41,10 @@ class Value(object):
41
41
"""A generic object with a list of preset fields."""
42
42
43
43
def __init__ (self , * args ):
44
+ if len (self ._fields ) != len (args ):
45
+ raise ValueError ('got {0} arguments for {1} fields for {2}: {3}'
46
+ .format (len (args ), len (self ._fields ),
47
+ self .__class__ .__name__ , self ._fields ))
44
48
vars (self ).update (zip (self ._fields , args ))
45
49
46
50
def __hash__ (self ):
@@ -59,7 +63,7 @@ class Definition(Value):
59
63
"""A Python source code definition (could be class, function, etc)."""
60
64
61
65
_fields = ('name' , '_source' , 'start' , 'end' , 'decorators' , 'docstring' ,
62
- 'children' , 'parent' )
66
+ 'children' , 'parent' , 'skipped_error_codes' )
63
67
64
68
_human = property (lambda self : humanize (type (self ).__name__ ))
65
69
kind = property (lambda self : self ._human .split ()[- 1 ])
@@ -87,14 +91,19 @@ def is_empty_or_comment(line):
87
91
return '' .join (reversed (list (filtered_src )))
88
92
89
93
def __str__ (self ):
90
- return 'in %s %s `%s`' % (self ._publicity , self ._human , self .name )
94
+ out = 'in {0} {1} `{2}`' .format (self ._publicity , self ._human ,
95
+ self .name )
96
+ if self .skipped_error_codes :
97
+ out += ' (skipping {0})' .format (self .skipped_error_codes )
98
+ return out
91
99
92
100
93
101
class Module (Definition ):
94
102
"""A Python source code module."""
95
103
96
104
_fields = ('name' , '_source' , 'start' , 'end' , 'decorators' , 'docstring' ,
97
- 'children' , 'parent' , '_all' , 'future_imports' )
105
+ 'children' , 'parent' , '_all' , 'future_imports' ,
106
+ 'skipped_error_codes' )
98
107
is_public = True
99
108
_nest = staticmethod (lambda s : {'def' : Function , 'class' : Class }[s ])
100
109
module = property (lambda self : self )
@@ -364,17 +373,17 @@ def parse_all(self):
364
373
if self .current .value not in '([' :
365
374
raise AllError ('Could not evaluate contents of __all__. ' )
366
375
if self .current .value == '[' :
367
- msg = ( "%s WARNING: __all__ is defined as a list, this means "
368
- "pydocstyle cannot reliably detect contents of the __all__ "
369
- "variable, because it can be mutated. Change __all__ to be "
370
- "an (immutable) tuple, to remove this warning. Note, "
371
- "pydocstyle uses __all__ to detect which definitions are "
372
- "public, to warn if public definitions are missing "
373
- "docstrings. If __all__ is a (mutable) list, pydocstyle "
374
- "cannot reliably assume its contents. pydocstyle will "
375
- "proceed assuming __all__ is not mutated. \n "
376
- % self . filename )
377
- sys . stderr . write ( msg )
376
+ sys . stderr . write (
377
+ "{0} WARNING: __all__ is defined as a list, this means "
378
+ "pydocstyle cannot reliably detect contents of the __all__ "
379
+ "variable, because it can be mutated. Change __all__ to be "
380
+ "an (immutable) tuple, to remove this warning. Note, "
381
+ "pydocstyle uses __all__ to detect which definitions are "
382
+ "public, to warn if public definitions are missing "
383
+ "docstrings. If __all__ is a (mutable) list, pydocstyle "
384
+ "cannot reliably assume its contents. pydocstyle will "
385
+ "proceed assuming __all__ is not mutated. \n "
386
+ . format ( self . filename ) )
378
387
self .consume (tk .OP )
379
388
380
389
self .all = []
@@ -386,17 +395,17 @@ def parse_all(self):
386
395
self .current .value == ',' ):
387
396
all_content += self .current .value
388
397
else :
389
- raise AllError ('Unexpected token kind in __all__: %r . ' %
390
- self .current .kind )
398
+ raise AllError ('Unexpected token kind in __all__: {0!r} . '
399
+ . format ( self .current .kind ) )
391
400
self .stream .move ()
392
401
self .consume (tk .OP )
393
402
all_content += ")"
394
403
try :
395
404
self .all = eval (all_content , {})
396
405
except BaseException as e :
397
406
raise AllError ('Could not evaluate contents of __all__.'
398
- '\b The value was %s . The exception was:\n %s '
399
- % (all_content , e ))
407
+ '\b The value was {0} . The exception was:\n {1} '
408
+ . format (all_content , e ))
400
409
401
410
def parse_module (self ):
402
411
"""Parse a module (and its children) and return a Module object."""
@@ -410,7 +419,7 @@ def parse_module(self):
410
419
if self .filename .endswith ('__init__.py' ):
411
420
cls = Package
412
421
module = cls (self .filename , self .source , start , end ,
413
- [], docstring , children , None , self .all )
422
+ [], docstring , children , None , self .all , None , '' )
414
423
for child in module .children :
415
424
child .parent = module
416
425
module .future_imports = self .future_imports
@@ -440,6 +449,7 @@ def parse_definition(self, class_):
440
449
else :
441
450
self .consume (tk .OP )
442
451
if self .current .kind in (tk .NEWLINE , tk .COMMENT ):
452
+ skipped_error_codes = self .parse_skip_comment ()
443
453
self .leapfrog (tk .INDENT )
444
454
assert self .current .kind != tk .INDENT
445
455
docstring = self .parse_docstring ()
@@ -451,20 +461,33 @@ def parse_definition(self, class_):
451
461
name )
452
462
end = self .line - 1
453
463
else : # one-liner definition
464
+ skipped_error_codes = ''
454
465
docstring = self .parse_docstring ()
455
466
decorators = [] # TODO
456
467
children = []
457
468
end = self .line
458
469
self .leapfrog (tk .NEWLINE )
459
470
definition = class_ (name , self .source , start , end ,
460
- decorators , docstring , children , None )
471
+ decorators , docstring , children , None ,
472
+ skipped_error_codes )
461
473
for child in definition .children :
462
474
child .parent = definition
463
475
self .log .debug ("finished parsing %s '%s'. Next token is %r (%s)" ,
464
476
class_ .__name__ , name , self .current .kind ,
465
477
self .current .value )
466
478
return definition
467
479
480
+ def parse_skip_comment (self ):
481
+ """Parse a definition comment for noqa skips."""
482
+ skipped_error_codes = ''
483
+ if self .current .kind == tk .COMMENT :
484
+ if 'noqa: ' in self .current .value :
485
+ skipped_error_codes = '' .join (
486
+ self .current .value .split ('noqa: ' )[1 :])
487
+ elif self .current .value .startswith ('# noqa' ):
488
+ skipped_error_codes = 'all'
489
+ return skipped_error_codes
490
+
468
491
def check_current (self , kind = None , value = None ):
469
492
"""Verify the current token is of type `kind` and equals `value`."""
470
493
msg = textwrap .dedent ("""
0 commit comments