Skip to content
This repository was archived by the owner on Nov 3, 2023. It is now read-only.

Commit 1979ae1

Browse files
committed
Refactored error definitions out of check methods.
1 parent 286f4ff commit 1979ae1

File tree

5 files changed

+129
-84
lines changed

5 files changed

+129
-84
lines changed

docs/snippets/error_code_table.rst

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
+--------------+--------------------------------------------------------------+
22
| **Missing docstrings** |
33
+--------------+--------------------------------------------------------------+
4-
| D100 | Public module missing. |
4+
| D100 | Missing docstring in public module. |
55
+--------------+--------------------------------------------------------------+
6-
| D101 | Public class missing. |
6+
| D101 | Missing docstring in public class. |
77
+--------------+--------------------------------------------------------------+
8-
| D102 | Public method missing. |
8+
| D102 | Missing docstring in public method. |
99
+--------------+--------------------------------------------------------------+
10-
| D103 | Public function missing. |
10+
| D103 | Missing docstring in public function. |
1111
+--------------+--------------------------------------------------------------+
1212
| **Whitespace issues** |
1313
+--------------+--------------------------------------------------------------+
@@ -17,19 +17,20 @@
1717
+--------------+--------------------------------------------------------------+
1818
| D202 | No blank lines allowed after docstring. |
1919
+--------------+--------------------------------------------------------------+
20-
| D203 | 1 blank required before class docstring. |
20+
| D203 | 1 blank line required before class docstring. |
2121
+--------------+--------------------------------------------------------------+
22-
| D204 | 1 blank required after class docstring. |
22+
| D204 | 1 blank line required after class docstring. |
2323
+--------------+--------------------------------------------------------------+
24-
| D205 | 1 blank required between summary line and description. |
24+
| D205 | 1 blank line required between summary line and description. |
2525
+--------------+--------------------------------------------------------------+
2626
| D206 | Docstring should be indented with spaces, not tabs. |
2727
+--------------+--------------------------------------------------------------+
2828
| D207 | Docstring under-indented. |
2929
+--------------+--------------------------------------------------------------+
3030
| D208 | Docstring over-indented. |
3131
+--------------+--------------------------------------------------------------+
32-
| D209 | Put multi-line docstring closing quotes on separate line. |
32+
| D209 | Multi-line docstring closing quotes should be on separate |
33+
| | line. |
3334
+--------------+--------------------------------------------------------------+
3435
| D210 | No whitespaces allowed surrounding docstring text. |
3536
+--------------+--------------------------------------------------------------+

pep257.py

Lines changed: 85 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -379,18 +379,30 @@ class Error(object):
379379

380380
"""Error in docstring style."""
381381

382+
# should be overridden by inheriting classes
383+
code = None
384+
_message = None
385+
382386
# Options that define how errors are printed:
383387
explain = False
384388
source = False
385389

386-
def __init__(self, message=None, final=False):
387-
self.message, self.is_final = message, final
388-
self.definition, self.explanation = [None, None]
390+
def __init__(self, *parameters):
391+
self.parameters = parameters
392+
self.definition = None
393+
self.explanation = None
394+
395+
def set_context(self, definition, explanation):
396+
self.definition = definition
397+
self.explanation = explanation
389398

390-
code = property(lambda self: self.message.partition(':')[0])
391399
filename = property(lambda self: self.definition.module.name)
392400
line = property(lambda self: self.definition.start)
393401

402+
@property
403+
def message(self):
404+
return '%s: %s' % (self.code, self._message) % self.parameters
405+
394406
@property
395407
def lines(self):
396408
source = ''
@@ -430,6 +442,52 @@ def __lt__(self, other):
430442
return (self.filename, self.line) < (other.filename, other.line)
431443

432444

445+
errors = []
446+
447+
448+
def register_error(error_cls):
449+
errors.append(error_cls)
450+
451+
452+
def error(code, message):
453+
_code = code
454+
455+
class _Error(Error):
456+
code = _code
457+
_message = message
458+
459+
register_error(_Error)
460+
return _Error
461+
462+
463+
D100 = error('D100', 'Missing docstring in public module')
464+
D101 = error('D101', 'Missing docstring in public class')
465+
D102 = error('D102', 'Missing docstring in public method')
466+
D103 = error('D103', 'Missing docstring in public function')
467+
D200 = error('D200', 'One-line docstring should fit on one line with quotes, '
468+
'found %s')
469+
D201 = error('D201', 'No blank lines allowed before function docstring, '
470+
'found %s')
471+
D202 = error('D202', 'No blank lines allowed after function docstring, '
472+
'found %s')
473+
D203 = error('D203', '1 blank line required before class docstring, found %s')
474+
D204 = error('D204', '1 blank line required after class docstring, found %s')
475+
D205 = error('D205', '1 blank line required between summary line and '
476+
'description, found %s')
477+
D206 = error('D206', 'Docstring should be indented with spaces, not tabs')
478+
D207 = error('D207', 'Docstring is under-indented')
479+
D208 = error('D208', 'Docstring is over-indented')
480+
D209 = error('D209', 'Multi-line docstring closing quotes should be on a '
481+
'separate line')
482+
D210 = error('D210', 'No whitespaces allowed surrounding docstring text')
483+
D300 = error('D300', 'Use """triple double quotes""", found %s-quotes')
484+
D301 = error('D301', 'Use r""" if any backslashes in a docstring')
485+
D302 = error('D302', 'Use u""" for Unicode docstrings')
486+
D400 = error('D400', 'First line should end with a period, not %r')
487+
D401 = error('D401', 'First line should be in imperative mood: %r, not %r')
488+
D402 = error('D402', 'First line should not be the function\'s "signature"')
489+
490+
433491
def get_option_parser():
434492
parser = OptionParser(version=__version__,
435493
usage='Usage: pep257 [options] [<file|dir>...]')
@@ -635,10 +693,8 @@ def check_source(self, source, filename):
635693
if error is not None:
636694
partition = check.__doc__.partition('.\n')
637695
message, _, explanation = partition
638-
if error.message is None:
639-
error.message = message
640-
error.explanation = explanation
641-
error.definition = definition
696+
error.set_context(explanation=explanation,
697+
definition=definition)
642698
yield error
643699
if check._terminal:
644700
terminate = True
@@ -668,9 +724,9 @@ def check_docstring_missing(self, definition, docstring):
668724
"""
669725
if (not docstring and definition.is_public or
670726
docstring and is_blank(eval(docstring))):
671-
codes = {Module: 'D100', Class: 'D101', NestedClass: 'D101',
672-
Method: 'D102', Function: 'D103', NestedFunction: 'D103'}
673-
return Error('%s: Docstring missing' % codes[type(definition)])
727+
codes = {Module: D100, Class: D101, NestedClass: D101,
728+
Method: D102, Function: D103, NestedFunction: D103}
729+
return codes[type(definition)]()
674730

675731
@check_for(Definition)
676732
def check_one_liners(self, definition, docstring):
@@ -685,8 +741,7 @@ def check_one_liners(self, definition, docstring):
685741
if len(lines) > 1:
686742
non_empty_lines = sum(1 for l in lines if not is_blank(l))
687743
if non_empty_lines == 1:
688-
return Error('D200: One-line docstring should not occupy '
689-
'%s lines' % len(lines))
744+
return D200(len(lines))
690745

691746
@check_for(Function)
692747
def check_no_blank_before(self, function, docstring): # def
@@ -704,13 +759,9 @@ def check_no_blank_before(self, function, docstring): # def
704759
blanks_before_count = sum(takewhile(bool, reversed(blanks_before)))
705760
blanks_after_count = sum(takewhile(bool, blanks_after))
706761
if blanks_before_count != 0:
707-
yield Error('D201: No blank lines allowed *before* %s '
708-
'docstring, found %s'
709-
% (function.kind, blanks_before_count))
762+
yield D201(blanks_before_count)
710763
if not all(blanks_after) and blanks_after_count != 0:
711-
yield Error('D202: No blank lines allowed *after* %s '
712-
'docstring, found %s'
713-
% (function.kind, blanks_after_count))
764+
yield D202(blanks_after_count)
714765

715766
@check_for(Class)
716767
def check_blank_before_after_class(slef, class_, docstring):
@@ -724,7 +775,7 @@ def check_blank_before_after_class(slef, class_, docstring):
724775
docstring.
725776
726777
"""
727-
# NOTE: this gives flase-positive in this case
778+
# NOTE: this gives false-positive in this case
728779
# class Foo:
729780
#
730781
# """Docstring."""
@@ -739,11 +790,9 @@ def check_blank_before_after_class(slef, class_, docstring):
739790
blanks_before_count = sum(takewhile(bool, reversed(blanks_before)))
740791
blanks_after_count = sum(takewhile(bool, blanks_after))
741792
if blanks_before_count != 1:
742-
yield Error('D203: Expected 1 blank line *before* class '
743-
'docstring, found %s' % blanks_before_count)
793+
yield D203(blanks_before_count)
744794
if not all(blanks_after) and blanks_after_count != 1:
745-
yield Error('D204: Expected 1 blank line *after* class '
746-
'docstring, found %s' % blanks_after_count)
795+
yield D204(blanks_after_count)
747796

748797
@check_for(Definition)
749798
def check_blank_after_summary(self, definition, docstring):
@@ -762,9 +811,7 @@ def check_blank_after_summary(self, definition, docstring):
762811
post_summary_blanks = list(map(is_blank, lines[1:]))
763812
blanks_count = sum(takewhile(bool, post_summary_blanks))
764813
if blanks_count != 1:
765-
yield Error('D205: Expected 1 blank line between summary '
766-
'line and description, found %s' %
767-
blanks_count)
814+
return D205(blanks_count)
768815

769816
@check_for(Definition)
770817
def check_indent(self, definition, docstring):
@@ -782,13 +829,12 @@ def check_indent(self, definition, docstring):
782829
lines = lines[1:] # First line does not need indent.
783830
indents = [leading_space(l) for l in lines if not is_blank(l)]
784831
if set(' \t') == set(''.join(indents) + indent):
785-
return Error('D206: Docstring indented with both tabs and '
786-
'spaces')
832+
yield D206()
787833
if (len(indents) > 1 and min(indents[:-1]) > indent
788834
or indents[-1] > indent):
789-
return Error('D208: Docstring is over-indented')
835+
yield D208()
790836
if min(indents) < indent:
791-
return Error('D207: Docstring is under-indented')
837+
yield D207()
792838

793839
@check_for(Definition)
794840
def check_newline_after_last_paragraph(self, definition, docstring):
@@ -802,8 +848,7 @@ def check_newline_after_last_paragraph(self, definition, docstring):
802848
lines = [l for l in eval(docstring).split('\n') if not is_blank(l)]
803849
if len(lines) > 1:
804850
if docstring.split("\n")[-1].strip() not in ['"""', "'''"]:
805-
return Error('D209: Put multi-line docstring closing '
806-
'quotes on separate line')
851+
return D209()
807852

808853
@check_for(Definition)
809854
def check_surrounding_whitespaces(self, definition, docstring):
@@ -812,8 +857,7 @@ def check_surrounding_whitespaces(self, definition, docstring):
812857
lines = eval(docstring).split('\n')
813858
if lines[0].startswith(' ') or \
814859
len(lines) == 1 and lines[0].endswith(' '):
815-
return Error("D210: No whitespaces allowed surrounding "
816-
"docstring text.")
860+
return D210()
817861

818862
@check_for(Definition)
819863
def check_triple_double_quotes(self, definition, docstring):
@@ -835,7 +879,7 @@ def check_triple_double_quotes(self, definition, docstring):
835879
return
836880
if docstring and not docstring.startswith(('"""', 'r"""', 'u"""')):
837881
quotes = "'''" if "'''" in docstring[:4] else "'"
838-
return Error('D300: Expected """-quotes, got %s-quotes' % quotes)
882+
return D300(quotes)
839883

840884
@check_for(Definition)
841885
def check_backslashes(self, definition, docstring):
@@ -848,7 +892,7 @@ def check_backslashes(self, definition, docstring):
848892
# Just check that docstring is raw, check_triple_double_quotes
849893
# ensures the correct quotes.
850894
if docstring and '\\' in docstring and not docstring.startswith('r'):
851-
return Error()
895+
return D301()
852896

853897
@check_for(Definition)
854898
def check_unicode_docstring(self, definition, docstring):
@@ -861,7 +905,7 @@ def check_unicode_docstring(self, definition, docstring):
861905
# ensures the correct quotes.
862906
if docstring and sys.version_info[0] <= 2:
863907
if not is_ascii(docstring) and not docstring.startswith('u'):
864-
return Error()
908+
return D302()
865909

866910
@check_for(Definition)
867911
def check_ends_with_period(self, definition, docstring):
@@ -873,8 +917,7 @@ def check_ends_with_period(self, definition, docstring):
873917
if docstring:
874918
summary_line = eval(docstring).strip().split('\n')[0]
875919
if not summary_line.endswith('.'):
876-
return Error("D400: First line should end with '.', not %r"
877-
% summary_line[-1])
920+
return D400(summary_line[-1])
878921

879922
@check_for(Function)
880923
def check_imperative_mood(self, function, docstring): # def context
@@ -890,8 +933,7 @@ def check_imperative_mood(self, function, docstring): # def context
890933
if stripped:
891934
first_word = stripped.split()[0]
892935
if first_word.endswith('s') and not first_word.endswith('ss'):
893-
return Error('D401: First line should be imperative: '
894-
'%r, not %r' % (first_word[:-1], first_word))
936+
return D401(first_word[:-1], first_word)
895937

896938
@check_for(Function)
897939
def check_no_signature(self, function, docstring): # def context
@@ -904,8 +946,7 @@ def check_no_signature(self, function, docstring): # def context
904946
if docstring:
905947
first_line = eval(docstring).strip().split('\n')[0]
906948
if function.name + '(' in first_line.replace(' ', ''):
907-
return Error("D402: First line should not be %s's signature"
908-
% function.kind)
949+
return D402()
909950

910951
# Somewhat hard to determine if return value is mentioned.
911952
# @check(Function)

0 commit comments

Comments
 (0)