@@ -379,18 +379,34 @@ class Error(object):
379
379
380
380
"""Error in docstring style."""
381
381
382
+ # should be overridden by inheriting classes
383
+ code = None
384
+ short_desc = None
385
+ context = None
386
+
382
387
# Options that define how errors are printed:
383
388
explain = False
384
389
source = False
385
390
386
- def __init__ (self , message = None , final = False ):
387
- self .message , self .is_final = message , final
388
- self .definition , self .explanation = [None , None ]
391
+ def __init__ (self , * parameters ):
392
+ self .parameters = parameters
393
+ self .definition = None
394
+ self .explanation = None
395
+
396
+ def set_context (self , definition , explanation ):
397
+ self .definition = definition
398
+ self .explanation = explanation
389
399
390
- code = property (lambda self : self .message .partition (':' )[0 ])
391
400
filename = property (lambda self : self .definition .module .name )
392
401
line = property (lambda self : self .definition .start )
393
402
403
+ @property
404
+ def message (self ):
405
+ ret = '%s: %s' % (self .code , self .short_desc )
406
+ if self .context is not None :
407
+ ret += ' (' + self .context % self .parameters + ')'
408
+ return ret
409
+
394
410
@property
395
411
def lines (self ):
396
412
source = ''
@@ -430,6 +446,100 @@ def __lt__(self, other):
430
446
return (self .filename , self .line ) < (other .filename , other .line )
431
447
432
448
449
+ class ErrorRegistry (object ):
450
+ groups = []
451
+
452
+ class ErrorGroup (object ):
453
+
454
+ def __init__ (self , prefix , name ):
455
+ self .prefix = prefix
456
+ self .name = name
457
+ self .errors = []
458
+
459
+ def create_error (self , error_code , error_desc , error_context = None ):
460
+ # TODO: check prefix
461
+
462
+ class _Error (Error ):
463
+ code = error_code
464
+ short_desc = error_desc
465
+ context = error_context
466
+
467
+ self .errors .append (_Error )
468
+ return _Error
469
+
470
+ @classmethod
471
+ def create_group (cls , prefix , name ):
472
+ group = cls .ErrorGroup (prefix , name )
473
+ cls .groups .append (group )
474
+ return group
475
+
476
+ @classmethod
477
+ def get_error_codes (cls ):
478
+ for group in cls .groups :
479
+ for error in group .errors :
480
+ yield error
481
+
482
+ @classmethod
483
+ def to_rst (cls ):
484
+ sep_line = '+' + 6 * '-' + '+' + '-' * 71 + '+\n '
485
+ blank_line = '|' + 78 * ' ' + '|\n '
486
+ table = ''
487
+ for group in cls .groups :
488
+ table += sep_line
489
+ table += blank_line
490
+ table += '|' + ('**%s**' % group .name ).center (78 ) + '|\n '
491
+ table += blank_line
492
+ for error in group .errors :
493
+ table += sep_line
494
+ table += ('|' + error .code .center (6 ) + '| ' +
495
+ error .short_desc .ljust (70 ) + '|\n ' )
496
+ table += sep_line
497
+ return table
498
+
499
+
500
+ D1xx = ErrorRegistry .create_group ('D1' , 'Missing Docstrings' )
501
+ D100 = D1xx .create_error ('D100' , 'Missing docstring in public module' )
502
+ D101 = D1xx .create_error ('D101' , 'Missing docstring in public class' )
503
+ D102 = D1xx .create_error ('D102' , 'Missing docstring in public method' )
504
+ D103 = D1xx .create_error ('D103' , 'Missing docstring in public function' )
505
+
506
+ D2xx = ErrorRegistry .create_group ('D2' , 'Whitespace Issues' )
507
+ D200 = D2xx .create_error ('D200' , 'One-line docstring should fit on one line '
508
+ 'with quotes' , 'found %s' )
509
+ D201 = D2xx .create_error ('D201' , 'No blank lines allowed before function '
510
+ 'docstring' , 'found %s' )
511
+ D202 = D2xx .create_error ('D202' , 'No blank lines allowed after function '
512
+ 'docstring' , 'found %s' )
513
+ D203 = D2xx .create_error ('D203' , '1 blank line required before class '
514
+ 'docstring' , 'found %s' )
515
+ D204 = D2xx .create_error ('D204' , '1 blank line required after class '
516
+ 'docstring' , 'found %s' )
517
+ D205 = D2xx .create_error ('D205' , '1 blank line required between summary line '
518
+ 'and description' , 'found %s' )
519
+ D206 = D2xx .create_error ('D206' , 'Docstring should be indented with spaces, '
520
+ 'not tabs' )
521
+ D207 = D2xx .create_error ('D207' , 'Docstring is under-indented' )
522
+ D208 = D2xx .create_error ('D208' , 'Docstring is over-indented' )
523
+ D209 = D2xx .create_error ('D209' , 'Multi-line docstring closing quotes should '
524
+ 'be on a separate line' )
525
+ D210 = D2xx .create_error ('D210' , 'No whitespaces allowed surrounding '
526
+ 'docstring text' )
527
+
528
+ D3xx = ErrorRegistry .create_group ('D3' , 'Quotes Issues' )
529
+ D300 = D3xx .create_error ('D300' , 'Use """triple double quotes"""' ,
530
+ 'found %s-quotes' )
531
+ D301 = D3xx .create_error ('D301' , 'Use r""" if any backslashes in a docstring' )
532
+ D302 = D3xx .create_error ('D302' , 'Use u""" for Unicode docstrings' )
533
+
534
+ D4xx = ErrorRegistry .create_group ('D4' , 'Docstring Content Issues' )
535
+ D400 = D4xx .create_error ('D400' , 'First line should end with a period' ,
536
+ 'not %r' )
537
+ D401 = D4xx .create_error ('D401' , 'First line should be in imperative mood' ,
538
+ '%r, not %r' )
539
+ D402 = D4xx .create_error ('D402' , 'First line should not be the function\' s '
540
+ '"signature"' )
541
+
542
+
433
543
def get_option_parser ():
434
544
parser = OptionParser (version = __version__ ,
435
545
usage = 'Usage: pep257 [options] [<file|dir>...]' )
@@ -634,10 +744,8 @@ def check_source(self, source, filename):
634
744
if error is not None :
635
745
partition = check .__doc__ .partition ('.\n ' )
636
746
message , _ , explanation = partition
637
- if error .message is None :
638
- error .message = message
639
- error .explanation = explanation
640
- error .definition = definition
747
+ error .set_context (explanation = explanation ,
748
+ definition = definition )
641
749
yield error
642
750
if check ._terminal :
643
751
terminate = True
@@ -667,9 +775,9 @@ def check_docstring_missing(self, definition, docstring):
667
775
"""
668
776
if (not docstring and definition .is_public or
669
777
docstring and is_blank (eval (docstring ))):
670
- codes = {Module : ' D100' , Class : ' D101' , NestedClass : ' D101' ,
671
- Method : ' D102' , Function : ' D103' , NestedFunction : ' D103' }
672
- return Error ( '%s: Docstring missing' % codes [type (definition )])
778
+ codes = {Module : D100 , Class : D101 , NestedClass : D101 ,
779
+ Method : D102 , Function : D103 , NestedFunction : D103 }
780
+ return codes [type (definition )]( )
673
781
674
782
@check_for (Definition )
675
783
def check_one_liners (self , definition , docstring ):
@@ -684,8 +792,7 @@ def check_one_liners(self, definition, docstring):
684
792
if len (lines ) > 1 :
685
793
non_empty_lines = sum (1 for l in lines if not is_blank (l ))
686
794
if non_empty_lines == 1 :
687
- return Error ('D200: One-line docstring should not occupy '
688
- '%s lines' % len (lines ))
795
+ return D200 (len (lines ))
689
796
690
797
@check_for (Function )
691
798
def check_no_blank_before (self , function , docstring ): # def
@@ -703,13 +810,9 @@ def check_no_blank_before(self, function, docstring): # def
703
810
blanks_before_count = sum (takewhile (bool , reversed (blanks_before )))
704
811
blanks_after_count = sum (takewhile (bool , blanks_after ))
705
812
if blanks_before_count != 0 :
706
- yield Error ('D201: No blank lines allowed *before* %s '
707
- 'docstring, found %s'
708
- % (function .kind , blanks_before_count ))
813
+ yield D201 (blanks_before_count )
709
814
if not all (blanks_after ) and blanks_after_count != 0 :
710
- yield Error ('D202: No blank lines allowed *after* %s '
711
- 'docstring, found %s'
712
- % (function .kind , blanks_after_count ))
815
+ yield D202 (blanks_after_count )
713
816
714
817
@check_for (Class )
715
818
def check_blank_before_after_class (slef , class_ , docstring ):
@@ -723,7 +826,7 @@ def check_blank_before_after_class(slef, class_, docstring):
723
826
docstring.
724
827
725
828
"""
726
- # NOTE: this gives flase -positive in this case
829
+ # NOTE: this gives false -positive in this case
727
830
# class Foo:
728
831
#
729
832
# """Docstring."""
@@ -738,11 +841,9 @@ def check_blank_before_after_class(slef, class_, docstring):
738
841
blanks_before_count = sum (takewhile (bool , reversed (blanks_before )))
739
842
blanks_after_count = sum (takewhile (bool , blanks_after ))
740
843
if blanks_before_count != 1 :
741
- yield Error ('D203: Expected 1 blank line *before* class '
742
- 'docstring, found %s' % blanks_before_count )
844
+ yield D203 (blanks_before_count )
743
845
if not all (blanks_after ) and blanks_after_count != 1 :
744
- yield Error ('D204: Expected 1 blank line *after* class '
745
- 'docstring, found %s' % blanks_after_count )
846
+ yield D204 (blanks_after_count )
746
847
747
848
@check_for (Definition )
748
849
def check_blank_after_summary (self , definition , docstring ):
@@ -761,9 +862,7 @@ def check_blank_after_summary(self, definition, docstring):
761
862
post_summary_blanks = list (map (is_blank , lines [1 :]))
762
863
blanks_count = sum (takewhile (bool , post_summary_blanks ))
763
864
if blanks_count != 1 :
764
- yield Error ('D205: Expected 1 blank line between summary '
765
- 'line and description, found %s' %
766
- blanks_count )
865
+ return D205 (blanks_count )
767
866
768
867
@check_for (Definition )
769
868
def check_indent (self , definition , docstring ):
@@ -781,13 +880,12 @@ def check_indent(self, definition, docstring):
781
880
lines = lines [1 :] # First line does not need indent.
782
881
indents = [leading_space (l ) for l in lines if not is_blank (l )]
783
882
if set (' \t ' ) == set ('' .join (indents ) + indent ):
784
- return Error ('D206: Docstring indented with both tabs and '
785
- 'spaces' )
883
+ yield D206 ()
786
884
if (len (indents ) > 1 and min (indents [:- 1 ]) > indent or
787
885
indents [- 1 ] > indent ):
788
- return Error ( ' D208: Docstring is over-indented' )
886
+ yield D208 ( )
789
887
if min (indents ) < indent :
790
- return Error ( ' D207: Docstring is under-indented' )
888
+ yield D207 ( )
791
889
792
890
@check_for (Definition )
793
891
def check_newline_after_last_paragraph (self , definition , docstring ):
@@ -801,8 +899,7 @@ def check_newline_after_last_paragraph(self, definition, docstring):
801
899
lines = [l for l in eval (docstring ).split ('\n ' ) if not is_blank (l )]
802
900
if len (lines ) > 1 :
803
901
if docstring .split ("\n " )[- 1 ].strip () not in ['"""' , "'''" ]:
804
- return Error ('D209: Put multi-line docstring closing '
805
- 'quotes on separate line' )
902
+ return D209 ()
806
903
807
904
@check_for (Definition )
808
905
def check_surrounding_whitespaces (self , definition , docstring ):
@@ -811,8 +908,7 @@ def check_surrounding_whitespaces(self, definition, docstring):
811
908
lines = eval (docstring ).split ('\n ' )
812
909
if lines [0 ].startswith (' ' ) or \
813
910
len (lines ) == 1 and lines [0 ].endswith (' ' ):
814
- return Error ("D210: No whitespaces allowed surrounding "
815
- "docstring text." )
911
+ return D210 ()
816
912
817
913
@check_for (Definition )
818
914
def check_triple_double_quotes (self , definition , docstring ):
@@ -834,7 +930,7 @@ def check_triple_double_quotes(self, definition, docstring):
834
930
return
835
931
if docstring and not docstring .startswith (('"""' , 'r"""' , 'u"""' )):
836
932
quotes = "'''" if "'''" in docstring [:4 ] else "'"
837
- return Error ( ' D300: Expected """-quotes, got %s-quotes' % quotes )
933
+ return D300 ( quotes )
838
934
839
935
@check_for (Definition )
840
936
def check_backslashes (self , definition , docstring ):
@@ -847,7 +943,7 @@ def check_backslashes(self, definition, docstring):
847
943
# Just check that docstring is raw, check_triple_double_quotes
848
944
# ensures the correct quotes.
849
945
if docstring and '\\ ' in docstring and not docstring .startswith ('r' ):
850
- return Error ()
946
+ return D301 ()
851
947
852
948
@check_for (Definition )
853
949
def check_unicode_docstring (self , definition , docstring ):
@@ -860,7 +956,7 @@ def check_unicode_docstring(self, definition, docstring):
860
956
# ensures the correct quotes.
861
957
if docstring and sys .version_info [0 ] <= 2 :
862
958
if not is_ascii (docstring ) and not docstring .startswith ('u' ):
863
- return Error ()
959
+ return D302 ()
864
960
865
961
@check_for (Definition )
866
962
def check_ends_with_period (self , definition , docstring ):
@@ -872,8 +968,7 @@ def check_ends_with_period(self, definition, docstring):
872
968
if docstring :
873
969
summary_line = eval (docstring ).strip ().split ('\n ' )[0 ]
874
970
if not summary_line .endswith ('.' ):
875
- return Error ("D400: First line should end with '.', not %r"
876
- % summary_line [- 1 ])
971
+ return D400 (summary_line [- 1 ])
877
972
878
973
@check_for (Function )
879
974
def check_imperative_mood (self , function , docstring ): # def context
@@ -889,8 +984,7 @@ def check_imperative_mood(self, function, docstring): # def context
889
984
if stripped :
890
985
first_word = stripped .split ()[0 ]
891
986
if first_word .endswith ('s' ) and not first_word .endswith ('ss' ):
892
- return Error ('D401: First line should be imperative: '
893
- '%r, not %r' % (first_word [:- 1 ], first_word ))
987
+ return D401 (first_word [:- 1 ], first_word )
894
988
895
989
@check_for (Function )
896
990
def check_no_signature (self , function , docstring ): # def context
@@ -903,8 +997,7 @@ def check_no_signature(self, function, docstring): # def context
903
997
if docstring :
904
998
first_line = eval (docstring ).strip ().split ('\n ' )[0 ]
905
999
if function .name + '(' in first_line .replace (' ' , '' ):
906
- return Error ("D402: First line should not be %s's signature"
907
- % function .kind )
1000
+ return D402 ()
908
1001
909
1002
# Somewhat hard to determine if return value is mentioned.
910
1003
# @check(Function)
0 commit comments