@@ -95,6 +95,10 @@ def leading_space(string):
95
95
class Value (object ):
96
96
97
97
def __init__ (self , * args ):
98
+ if len (self ._fields ) != len (args ):
99
+ raise ValueError ('got {0} arguments for {1} fields for {2}: {3}'
100
+ .format (len (args ), len (self ._fields ),
101
+ self .__class__ .__name__ , self ._fields ))
98
102
vars (self ).update (zip (self ._fields , args ))
99
103
100
104
def __hash__ (self ):
@@ -112,7 +116,7 @@ def __repr__(self):
112
116
class Definition (Value ):
113
117
114
118
_fields = ('name' , '_source' , 'start' , 'end' , 'decorators' , 'docstring' ,
115
- 'children' , 'parent' )
119
+ 'children' , 'parent' , 'skipped_error_codes' )
116
120
117
121
_human = property (lambda self : humanize (type (self ).__name__ ))
118
122
kind = property (lambda self : self ._human .split ()[- 1 ])
@@ -140,13 +144,18 @@ def is_empty_or_comment(line):
140
144
return '' .join (reversed (list (filtered_src )))
141
145
142
146
def __str__ (self ):
143
- return 'in %s %s `%s`' % (self ._publicity , self ._human , self .name )
147
+ out = 'in {0} {1} `{2}`' .format (self ._publicity , self ._human ,
148
+ self .name )
149
+ if self .skipped_error_codes :
150
+ out += ' (skipping {0})' .format (self .skipped_error_codes )
151
+ return out
144
152
145
153
146
154
class Module (Definition ):
147
155
148
156
_fields = ('name' , '_source' , 'start' , 'end' , 'decorators' , 'docstring' ,
149
- 'children' , 'parent' , '_all' , 'future_imports' )
157
+ 'children' , 'parent' , '_all' , 'future_imports' ,
158
+ 'skipped_error_codes' )
150
159
is_public = True
151
160
_nest = staticmethod (lambda s : {'def' : Function , 'class' : Class }[s ])
152
161
module = property (lambda self : self )
@@ -387,17 +396,17 @@ def parse_all(self):
387
396
if self .current .value not in '([' :
388
397
raise AllError ('Could not evaluate contents of __all__. ' )
389
398
if self .current .value == '[' :
390
- msg = ( "%s WARNING: __all__ is defined as a list, this means "
391
- "pydocstyle cannot reliably detect contents of the __all__ "
392
- "variable, because it can be mutated. Change __all__ to be "
393
- "an (immutable) tuple, to remove this warning. Note, "
394
- "pydocstyle uses __all__ to detect which definitions are "
395
- "public, to warn if public definitions are missing "
396
- "docstrings. If __all__ is a (mutable) list, pydocstyle "
397
- "cannot reliably assume its contents. pydocstyle will "
398
- "proceed assuming __all__ is not mutated. \n "
399
- % self . filename )
400
- sys . stderr . write ( msg )
399
+ sys . stderr . write (
400
+ "{0} WARNING: __all__ is defined as a list, this means "
401
+ "pydocstyle cannot reliably detect contents of the __all__ "
402
+ "variable, because it can be mutated. Change __all__ to be "
403
+ "an (immutable) tuple, to remove this warning. Note, "
404
+ "pydocstyle uses __all__ to detect which definitions are "
405
+ "public, to warn if public definitions are missing "
406
+ "docstrings. If __all__ is a (mutable) list, pydocstyle "
407
+ "cannot reliably assume its contents. pydocstyle will "
408
+ "proceed assuming __all__ is not mutated. \n "
409
+ . format ( self . filename ) )
401
410
self .consume (tk .OP )
402
411
403
412
self .all = []
@@ -409,17 +418,17 @@ def parse_all(self):
409
418
self .current .value == ',' ):
410
419
all_content += self .current .value
411
420
else :
412
- raise AllError ('Unexpected token kind in __all__: %r . ' %
413
- self .current .kind )
421
+ raise AllError ('Unexpected token kind in __all__: {0!r} . '
422
+ . format ( self .current .kind ) )
414
423
self .stream .move ()
415
424
self .consume (tk .OP )
416
425
all_content += ")"
417
426
try :
418
427
self .all = eval (all_content , {})
419
428
except BaseException as e :
420
429
raise AllError ('Could not evaluate contents of __all__.'
421
- '\b The value was %s . The exception was:\n %s '
422
- % (all_content , e ))
430
+ '\b The value was {0} . The exception was:\n {1} '
431
+ . format (all_content , e ))
423
432
424
433
def parse_module (self ):
425
434
"""Parse a module (and its children) and return a Module object."""
@@ -433,7 +442,7 @@ def parse_module(self):
433
442
if self .filename .endswith ('__init__.py' ):
434
443
cls = Package
435
444
module = cls (self .filename , self .source , start , end ,
436
- [], docstring , children , None , self .all )
445
+ [], docstring , children , None , self .all , None , '' )
437
446
for child in module .children :
438
447
child .parent = module
439
448
module .future_imports = self .future_imports
@@ -463,6 +472,7 @@ def parse_definition(self, class_):
463
472
else :
464
473
self .consume (tk .OP )
465
474
if self .current .kind in (tk .NEWLINE , tk .COMMENT ):
475
+ skipped_error_codes = self .parse_skip_comment ()
466
476
self .leapfrog (tk .INDENT )
467
477
assert self .current .kind != tk .INDENT
468
478
docstring = self .parse_docstring ()
@@ -473,20 +483,33 @@ def parse_definition(self, class_):
473
483
log .debug ("finished parsing nested definitions for '%s'" , name )
474
484
end = self .line - 1
475
485
else : # one-liner definition
486
+ skipped_error_codes = ''
476
487
docstring = self .parse_docstring ()
477
488
decorators = [] # TODO
478
489
children = []
479
490
end = self .line
480
491
self .leapfrog (tk .NEWLINE )
481
492
definition = class_ (name , self .source , start , end ,
482
- decorators , docstring , children , None )
493
+ decorators , docstring , children , None ,
494
+ skipped_error_codes )
483
495
for child in definition .children :
484
496
child .parent = definition
485
497
log .debug ("finished parsing %s '%s'. Next token is %r (%s)" ,
486
498
class_ .__name__ , name , self .current .kind ,
487
499
self .current .value )
488
500
return definition
489
501
502
+ def parse_skip_comment (self ):
503
+ """Parse a definition comment for noqa skips."""
504
+ skipped_error_codes = ''
505
+ if self .current .kind == tk .COMMENT :
506
+ if 'noqa: ' in self .current .value :
507
+ skipped_error_codes = '' .join (
508
+ self .current .value .split ('noqa: ' )[1 :])
509
+ elif self .current .value .startswith ('# noqa' ):
510
+ skipped_error_codes = 'all'
511
+ return skipped_error_codes
512
+
490
513
def check_current (self , kind = None , value = None ):
491
514
msg = textwrap .dedent ("""
492
515
Unexpected token at line {self.line}:
@@ -583,9 +606,9 @@ def set_context(self, definition, explanation):
583
606
584
607
@property
585
608
def message (self ):
586
- ret = '%s: %s' % (self .code , self .short_desc )
609
+ ret = '{0}: {1}' . format (self .code , self .short_desc )
587
610
if self .context is not None :
588
- ret += ' (' + self .context % self .parameters + ')'
611
+ ret += ' (' + self .context . format ( * self .parameters ) + ')'
589
612
return ret
590
613
591
614
@property
@@ -601,7 +624,8 @@ def lines(self):
601
624
numbers_width = len (str (numbers_width ))
602
625
numbers_width = 6
603
626
for n , line in enumerate (lines_stripped ):
604
- source += '%*d: %s' % (numbers_width , n + offset , line )
627
+ source += '{{0}}{0}: {{1}}' .format (numbers_width ).format (
628
+ n + offset , line )
605
629
if n > 5 :
606
630
source += ' ...\n '
607
631
break
@@ -610,16 +634,16 @@ def lines(self):
610
634
def __str__ (self ):
611
635
self .explanation = '\n ' .join (l for l in self .explanation .split ('\n ' )
612
636
if not is_blank (l ))
613
- template = '%( filename)s:%( line)s %( definition)s :\n %( message)s '
637
+ template = '{ filename}:{ line} { definition} :\n { message} '
614
638
if self .source and self .explain :
615
- template += '\n \n %( explanation)s \n \n %( lines)s \n '
639
+ template += '\n \n { explanation} \n \n { lines} \n '
616
640
elif self .source and not self .explain :
617
- template += '\n \n %( lines)s \n '
641
+ template += '\n \n { lines} \n '
618
642
elif self .explain and not self .source :
619
- template += '\n \n %( explanation)s \n \n '
620
- return template % dict ((name , getattr (self , name )) for name in
643
+ template += '\n \n { explanation} \n \n '
644
+ return template . format ( ** dict ((name , getattr (self , name )) for name in
621
645
['filename' , 'line' , 'definition' , 'message' ,
622
- 'explanation' , 'lines' ])
646
+ 'explanation' , 'lines' ]))
623
647
624
648
__repr__ = __str__
625
649
@@ -668,7 +692,7 @@ def to_rst(cls):
668
692
for group in cls .groups :
669
693
table += sep_line
670
694
table += blank_line
671
- table += '|' + ( '**%s **' % group .name ).center (78 ) + '|\n '
695
+ table += '|' + '**{0} **' . format ( group .name ).center (78 ) + '|\n '
672
696
table += blank_line
673
697
for error in group .errors :
674
698
table += sep_line
@@ -688,17 +712,17 @@ def to_rst(cls):
688
712
689
713
D2xx = ErrorRegistry .create_group ('D2' , 'Whitespace Issues' )
690
714
D200 = D2xx .create_error ('D200' , 'One-line docstring should fit on one line '
691
- 'with quotes' , 'found %s ' )
715
+ 'with quotes' , 'found {0} ' )
692
716
D201 = D2xx .create_error ('D201' , 'No blank lines allowed before function '
693
- 'docstring' , 'found %s ' )
717
+ 'docstring' , 'found {0} ' )
694
718
D202 = D2xx .create_error ('D202' , 'No blank lines allowed after function '
695
- 'docstring' , 'found %s ' )
719
+ 'docstring' , 'found {0} ' )
696
720
D203 = D2xx .create_error ('D203' , '1 blank line required before class '
697
- 'docstring' , 'found %s ' )
721
+ 'docstring' , 'found {0} ' )
698
722
D204 = D2xx .create_error ('D204' , '1 blank line required after class '
699
- 'docstring' , 'found %s ' )
723
+ 'docstring' , 'found {0} ' )
700
724
D205 = D2xx .create_error ('D205' , '1 blank line required between summary line '
701
- 'and description' , 'found %s ' )
725
+ 'and description' , 'found {0} ' )
702
726
D206 = D2xx .create_error ('D206' , 'Docstring should be indented with spaces, '
703
727
'not tabs' )
704
728
D207 = D2xx .create_error ('D207' , 'Docstring is under-indented' )
@@ -708,27 +732,27 @@ def to_rst(cls):
708
732
D210 = D2xx .create_error ('D210' , 'No whitespaces allowed surrounding '
709
733
'docstring text' )
710
734
D211 = D2xx .create_error ('D211' , 'No blank lines allowed before class '
711
- 'docstring' , 'found %s ' )
735
+ 'docstring' , 'found {0} ' )
712
736
D212 = D2xx .create_error ('D212' , 'Multi-line docstring summary should start '
713
737
'at the first line' )
714
738
D213 = D2xx .create_error ('D213' , 'Multi-line docstring summary should start '
715
739
'at the second line' )
716
740
717
741
D3xx = ErrorRegistry .create_group ('D3' , 'Quotes Issues' )
718
742
D300 = D3xx .create_error ('D300' , 'Use """triple double quotes"""' ,
719
- 'found %s -quotes' )
743
+ 'found {0} -quotes' )
720
744
D301 = D3xx .create_error ('D301' , 'Use r""" if any backslashes in a docstring' )
721
745
D302 = D3xx .create_error ('D302' , 'Use u""" for Unicode docstrings' )
722
746
723
747
D4xx = ErrorRegistry .create_group ('D4' , 'Docstring Content Issues' )
724
748
D400 = D4xx .create_error ('D400' , 'First line should end with a period' ,
725
- 'not %r ' )
749
+ 'not {0!r} ' )
726
750
D401 = D4xx .create_error ('D401' , 'First line should be in imperative mood' ,
727
- '%r , not %r ' )
751
+ '{0!r} , not {1!r} ' )
728
752
D402 = D4xx .create_error ('D402' , 'First line should not be the function\' s '
729
753
'"signature"' )
730
754
D403 = D4xx .create_error ('D403' , 'First word of the first line should be '
731
- 'properly capitalized' , '%r , not %r ' )
755
+ 'properly capitalized' , '{0!r} , not {1!r} ' )
732
756
D404 = D4xx .create_error ('D404' , 'First word of the docstring should not '
733
757
'be `This`' )
734
758
@@ -1365,7 +1389,7 @@ def run_pydocstyle(use_pep257=False):
1365
1389
code = ReturnCode .no_violations_found
1366
1390
count = 0
1367
1391
for error in errors :
1368
- sys .stderr .write ('%s \n ' % error )
1392
+ sys .stderr .write ('{0} \n ' . format ( error ) )
1369
1393
code = ReturnCode .violations_found
1370
1394
count += 1
1371
1395
if run_conf .count :
@@ -1400,10 +1424,14 @@ def check_source(self, source, filename):
1400
1424
for check in self .checks :
1401
1425
terminate = False
1402
1426
if isinstance (definition , check ._check_for ):
1403
- error = check (None , definition , definition .docstring )
1427
+ if definition .skipped_error_codes != 'all' :
1428
+ error = check (None , definition , definition .docstring )
1429
+ else :
1430
+ error = None
1404
1431
errors = error if hasattr (error , '__iter__' ) else [error ]
1405
1432
for error in errors :
1406
- if error is not None :
1433
+ if error is not None and error .code not in \
1434
+ definition .skipped_error_codes :
1407
1435
partition = check .__doc__ .partition ('.\n ' )
1408
1436
message , _ , explanation = partition
1409
1437
error .set_context (explanation = explanation ,
0 commit comments