4
4
import string
5
5
import sys
6
6
import tokenize as tk
7
- from itertools import takewhile , tee
7
+ from itertools import takewhile
8
8
from re import compile as re
9
9
from collections import namedtuple
10
10
11
11
from . import violations
12
12
from .config import IllegalConfiguration
13
13
from .parser import (Package , Module , Class , NestedClass , Definition , AllError ,
14
14
Method , Function , NestedFunction , Parser , StringIO )
15
- from .utils import log , is_blank
16
-
17
- try :
18
- from itertools import zip_longest
19
- except ImportError :
20
- from itertools import izip_longest as zip_longest
15
+ from .utils import log , is_blank , pairwise
21
16
22
17
23
18
__all__ = ('check' , )
@@ -39,16 +34,6 @@ def decorator(f):
39
34
return decorator
40
35
41
36
42
- def pairwise (iterable , default_value ):
43
- """Return pairs of items from `iterable`.
44
-
45
- pairwise([1, 2, 3], default_value=None) -> (1, 2) (2, 3), (3, None)
46
- """
47
- a , b = tee (iterable )
48
- _ = next (b , default_value )
49
- return zip_longest (a , b , fillvalue = default_value )
50
-
51
-
52
37
class ConventionChecker (object ):
53
38
"""Checker for PEP 257 and numpy conventions.
54
39
@@ -489,48 +474,62 @@ def _check_section_underline(cls, section_name, context, indentation):
489
474
* The indentation of the dashed line is equal to the docstring's
490
475
indentation (D215).
491
476
"""
492
- dash_line_found = False
493
- next_non_empty_line_offset = 0
477
+ blank_lines_after_header = 0
494
478
495
479
for line in context .following_lines :
496
- line_set = '' .join (set (line .strip ()))
497
- if not is_blank (line_set ):
498
- dash_line_found = line_set == '-'
480
+ if not is_blank (line ):
499
481
break
500
- next_non_empty_line_offset += 1
482
+ blank_lines_after_header += 1
483
+ else :
484
+ # There are only blank lines after the header.
485
+ yield violations .D407 (section_name )
486
+ return
487
+
488
+ non_empty_line = context .following_lines [blank_lines_after_header ]
489
+ dash_line_found = '' .join (set (non_empty_line .strip ())) == '-'
501
490
502
491
if not dash_line_found :
503
492
yield violations .D407 (section_name )
504
- if next_non_empty_line_offset > 0 :
493
+ if blank_lines_after_header > 0 :
505
494
yield violations .D412 (section_name )
506
495
else :
507
- if next_non_empty_line_offset > 0 :
496
+ if blank_lines_after_header > 0 :
508
497
yield violations .D408 (section_name )
509
498
510
- dash_line = context .following_lines [next_non_empty_line_offset ]
511
- if dash_line .strip () != "-" * len (section_name ):
499
+ if non_empty_line .strip () != "-" * len (section_name ):
512
500
yield violations .D409 (len (section_name ),
513
501
section_name ,
514
- len (dash_line .strip ()))
502
+ len (non_empty_line .strip ()))
515
503
516
- if leading_space (dash_line ) > indentation :
504
+ if leading_space (non_empty_line ) > indentation :
517
505
yield violations .D215 (section_name )
518
506
519
- if next_non_empty_line_offset + 1 < len (context .following_lines ):
507
+ line_after_dashes_index = blank_lines_after_header + 1
508
+ # If the line index after the dashes is in range (perhaps we have
509
+ # a header + underline followed by another section header).
510
+ if line_after_dashes_index < len (context .following_lines ):
520
511
line_after_dashes = \
521
- context .following_lines [next_non_empty_line_offset + 1 ]
512
+ context .following_lines [line_after_dashes_index ]
522
513
if is_blank (line_after_dashes ):
523
- yield violations .D412 (section_name )
514
+ rest_of_lines = \
515
+ context .following_lines [line_after_dashes_index :]
516
+ if not is_blank ('' .join (rest_of_lines )):
517
+ yield violations .D412 (section_name )
518
+ else :
519
+ yield violations .D414 (section_name )
520
+ else :
521
+ yield violations .D414 (section_name )
522
+
524
523
525
524
@classmethod
526
525
def _check_section (cls , docstring , definition , context ):
527
- """D4{05,06,10,11}, D214: Section name checks.
526
+ """D4{05,06,10,11,13 }, D214: Section name checks.
528
527
529
528
Check for valid section names. Checks that:
530
529
* The section name is properly capitalized (D405).
531
530
* The section is not over-indented (D214).
532
531
* The section name has no superfluous suffix to it (D406).
533
- * There's a blank line after the section (D410).
532
+ * There's a blank line after the section (D410, D413 ).
534
533
* There's a blank line before the section (D411).
535
534
536
535
Also yields all the errors from `_check_section_underline`.
@@ -551,7 +550,10 @@ def _check_section(cls, docstring, definition, context):
551
550
552
551
if (not context .following_lines or
553
552
not is_blank (context .following_lines [- 1 ])):
554
- yield violations .D410 (capitalized_section )
553
+ if context .is_last_section :
554
+ yield violations .D413 (capitalized_section )
555
+ else :
556
+ yield violations .D410 (capitalized_section )
555
557
556
558
if not is_blank (context .previous_line ):
557
559
yield violations .D411 (capitalized_section )
@@ -601,15 +603,17 @@ def _suspected_as_section(_line):
601
603
'previous_line' ,
602
604
'line' ,
603
605
'following_lines' ,
604
- 'original_index' ))
606
+ 'original_index' ,
607
+ 'is_last_section' ))
605
608
606
609
# First - create a list of possible contexts. Note that the
607
610
# `following_linex` member is until the end of the docstring.
608
611
contexts = (SectionContext (self ._get_leading_words (lines [i ].strip ()),
609
612
lines [i - 1 ],
610
613
lines [i ],
611
614
lines [i + 1 :],
612
- i )
615
+ i ,
616
+ False )
613
617
for i in suspected_section_indices )
614
618
615
619
# Now that we have manageable objects - rule out false positives.
@@ -623,7 +627,8 @@ def _suspected_as_section(_line):
623
627
a .previous_line ,
624
628
a .line ,
625
629
lines [a .original_index + 1 :end ],
626
- a .original_index )
630
+ a .original_index ,
631
+ b is None )
627
632
for err in self ._check_section (docstring , definition , new_ctx ):
628
633
yield err
629
634
0 commit comments