@@ -95,6 +95,10 @@ def leading_space(string):
9595class Value (object ):
9696
9797 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 ))
98102 vars (self ).update (zip (self ._fields , args ))
99103
100104 def __hash__ (self ):
@@ -112,7 +116,7 @@ def __repr__(self):
112116class Definition (Value ):
113117
114118 _fields = ('name' , '_source' , 'start' , 'end' , 'decorators' , 'docstring' ,
115- 'children' , 'parent' )
119+ 'children' , 'parent' , 'skipped_error_codes' )
116120
117121 _human = property (lambda self : humanize (type (self ).__name__ ))
118122 kind = property (lambda self : self ._human .split ()[- 1 ])
@@ -140,13 +144,18 @@ def is_empty_or_comment(line):
140144 return '' .join (reversed (list (filtered_src )))
141145
142146 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
144152
145153
146154class Module (Definition ):
147155
148156 _fields = ('name' , '_source' , 'start' , 'end' , 'decorators' , 'docstring' ,
149- 'children' , 'parent' , '_all' , 'future_imports' )
157+ 'children' , 'parent' , '_all' , 'future_imports' ,
158+ 'skipped_error_codes' )
150159 is_public = True
151160 _nest = staticmethod (lambda s : {'def' : Function , 'class' : Class }[s ])
152161 module = property (lambda self : self )
@@ -387,17 +396,17 @@ def parse_all(self):
387396 if self .current .value not in '([' :
388397 raise AllError ('Could not evaluate contents of __all__. ' )
389398 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 ) )
401410 self .consume (tk .OP )
402411
403412 self .all = []
@@ -409,17 +418,17 @@ def parse_all(self):
409418 self .current .value == ',' ):
410419 all_content += self .current .value
411420 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 ) )
414423 self .stream .move ()
415424 self .consume (tk .OP )
416425 all_content += ")"
417426 try :
418427 self .all = eval (all_content , {})
419428 except BaseException as e :
420429 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 ))
423432
424433 def parse_module (self ):
425434 """Parse a module (and its children) and return a Module object."""
@@ -433,7 +442,7 @@ def parse_module(self):
433442 if self .filename .endswith ('__init__.py' ):
434443 cls = Package
435444 module = cls (self .filename , self .source , start , end ,
436- [], docstring , children , None , self .all )
445+ [], docstring , children , None , self .all , None , '' )
437446 for child in module .children :
438447 child .parent = module
439448 module .future_imports = self .future_imports
@@ -463,6 +472,7 @@ def parse_definition(self, class_):
463472 else :
464473 self .consume (tk .OP )
465474 if self .current .kind in (tk .NEWLINE , tk .COMMENT ):
475+ skipped_error_codes = self .parse_skip_comment ()
466476 self .leapfrog (tk .INDENT )
467477 assert self .current .kind != tk .INDENT
468478 docstring = self .parse_docstring ()
@@ -473,20 +483,33 @@ def parse_definition(self, class_):
473483 log .debug ("finished parsing nested definitions for '%s'" , name )
474484 end = self .line - 1
475485 else : # one-liner definition
486+ skipped_error_codes = ''
476487 docstring = self .parse_docstring ()
477488 decorators = [] # TODO
478489 children = []
479490 end = self .line
480491 self .leapfrog (tk .NEWLINE )
481492 definition = class_ (name , self .source , start , end ,
482- decorators , docstring , children , None )
493+ decorators , docstring , children , None ,
494+ skipped_error_codes )
483495 for child in definition .children :
484496 child .parent = definition
485497 log .debug ("finished parsing %s '%s'. Next token is %r (%s)" ,
486498 class_ .__name__ , name , self .current .kind ,
487499 self .current .value )
488500 return definition
489501
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+
490513 def check_current (self , kind = None , value = None ):
491514 msg = textwrap .dedent ("""
492515 Unexpected token at line {self.line}:
@@ -583,9 +606,9 @@ def set_context(self, definition, explanation):
583606
584607 @property
585608 def message (self ):
586- ret = '%s: %s' % (self .code , self .short_desc )
609+ ret = '{0}: {1}' . format (self .code , self .short_desc )
587610 if self .context is not None :
588- ret += ' (' + self .context % self .parameters + ')'
611+ ret += ' (' + self .context . format ( * self .parameters ) + ')'
589612 return ret
590613
591614 @property
@@ -601,7 +624,8 @@ def lines(self):
601624 numbers_width = len (str (numbers_width ))
602625 numbers_width = 6
603626 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 )
605629 if n > 5 :
606630 source += ' ...\n '
607631 break
@@ -610,16 +634,16 @@ def lines(self):
610634 def __str__ (self ):
611635 self .explanation = '\n ' .join (l for l in self .explanation .split ('\n ' )
612636 if not is_blank (l ))
613- template = '%( filename)s:%( line)s %( definition)s :\n %( message)s '
637+ template = '{ filename}:{ line} { definition} :\n { message} '
614638 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 '
616640 elif self .source and not self .explain :
617- template += '\n \n %( lines)s \n '
641+ template += '\n \n { lines} \n '
618642 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
621645 ['filename' , 'line' , 'definition' , 'message' ,
622- 'explanation' , 'lines' ])
646+ 'explanation' , 'lines' ]))
623647
624648 __repr__ = __str__
625649
@@ -668,7 +692,7 @@ def to_rst(cls):
668692 for group in cls .groups :
669693 table += sep_line
670694 table += blank_line
671- table += '|' + ( '**%s **' % group .name ).center (78 ) + '|\n '
695+ table += '|' + '**{0} **' . format ( group .name ).center (78 ) + '|\n '
672696 table += blank_line
673697 for error in group .errors :
674698 table += sep_line
@@ -688,17 +712,17 @@ def to_rst(cls):
688712
689713D2xx = ErrorRegistry .create_group ('D2' , 'Whitespace Issues' )
690714D200 = D2xx .create_error ('D200' , 'One-line docstring should fit on one line '
691- 'with quotes' , 'found %s ' )
715+ 'with quotes' , 'found {0} ' )
692716D201 = D2xx .create_error ('D201' , 'No blank lines allowed before function '
693- 'docstring' , 'found %s ' )
717+ 'docstring' , 'found {0} ' )
694718D202 = D2xx .create_error ('D202' , 'No blank lines allowed after function '
695- 'docstring' , 'found %s ' )
719+ 'docstring' , 'found {0} ' )
696720D203 = D2xx .create_error ('D203' , '1 blank line required before class '
697- 'docstring' , 'found %s ' )
721+ 'docstring' , 'found {0} ' )
698722D204 = D2xx .create_error ('D204' , '1 blank line required after class '
699- 'docstring' , 'found %s ' )
723+ 'docstring' , 'found {0} ' )
700724D205 = D2xx .create_error ('D205' , '1 blank line required between summary line '
701- 'and description' , 'found %s ' )
725+ 'and description' , 'found {0} ' )
702726D206 = D2xx .create_error ('D206' , 'Docstring should be indented with spaces, '
703727 'not tabs' )
704728D207 = D2xx .create_error ('D207' , 'Docstring is under-indented' )
@@ -708,27 +732,27 @@ def to_rst(cls):
708732D210 = D2xx .create_error ('D210' , 'No whitespaces allowed surrounding '
709733 'docstring text' )
710734D211 = D2xx .create_error ('D211' , 'No blank lines allowed before class '
711- 'docstring' , 'found %s ' )
735+ 'docstring' , 'found {0} ' )
712736D212 = D2xx .create_error ('D212' , 'Multi-line docstring summary should start '
713737 'at the first line' )
714738D213 = D2xx .create_error ('D213' , 'Multi-line docstring summary should start '
715739 'at the second line' )
716740
717741D3xx = ErrorRegistry .create_group ('D3' , 'Quotes Issues' )
718742D300 = D3xx .create_error ('D300' , 'Use """triple double quotes"""' ,
719- 'found %s -quotes' )
743+ 'found {0} -quotes' )
720744D301 = D3xx .create_error ('D301' , 'Use r""" if any backslashes in a docstring' )
721745D302 = D3xx .create_error ('D302' , 'Use u""" for Unicode docstrings' )
722746
723747D4xx = ErrorRegistry .create_group ('D4' , 'Docstring Content Issues' )
724748D400 = D4xx .create_error ('D400' , 'First line should end with a period' ,
725- 'not %r ' )
749+ 'not {0!r} ' )
726750D401 = D4xx .create_error ('D401' , 'First line should be in imperative mood' ,
727- '%r , not %r ' )
751+ '{0!r} , not {1!r} ' )
728752D402 = D4xx .create_error ('D402' , 'First line should not be the function\' s '
729753 '"signature"' )
730754D403 = 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} ' )
732756D404 = D4xx .create_error ('D404' , 'First word of the docstring should not '
733757 'be `This`' )
734758
@@ -1365,7 +1389,7 @@ def run_pydocstyle(use_pep257=False):
13651389 code = ReturnCode .no_violations_found
13661390 count = 0
13671391 for error in errors :
1368- sys .stderr .write ('%s \n ' % error )
1392+ sys .stderr .write ('{0} \n ' . format ( error ) )
13691393 code = ReturnCode .violations_found
13701394 count += 1
13711395 if run_conf .count :
@@ -1400,10 +1424,14 @@ def check_source(self, source, filename):
14001424 for check in self .checks :
14011425 terminate = False
14021426 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
14041431 errors = error if hasattr (error , '__iter__' ) else [error ]
14051432 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 :
14071435 partition = check .__doc__ .partition ('.\n ' )
14081436 message , _ , explanation = partition
14091437 error .set_context (explanation = explanation ,
0 commit comments