@@ -717,7 +717,10 @@ def to_rst(cls):
717
717
'"signature"' )
718
718
D403 = D4xx .create_error ('D403' , 'First word of the first line should be '
719
719
'properly capitalized' , '%r, not %r' )
720
-
720
+ D404 = D4xx .create_error ('D404' , 'Section name should be properly capitalized' ,
721
+ '%r, not %r' )
722
+ D405 = D4xx .create_error ('D405' , 'Section underline should match the length of '
723
+ 'the section\' s name' , 'len(%r) == %r, not %r' )
721
724
722
725
class AttrDict (dict ):
723
726
def __getattr__ (self , item ):
@@ -1711,6 +1714,100 @@ def SKIP_check_return_type(self, function, docstring):
1711
1714
if 'return' not in docstring .lower ():
1712
1715
return Error ()
1713
1716
1717
+ @check_for (Function )
1718
+ def check_numpy (self , function , docstring ):
1719
+ """D403: First word of the first line should be properly capitalized.
1720
+
1721
+ The [first line of a] docstring is a phrase ending in a period.
1722
+
1723
+ """
1724
+ SECTIONS = ['Summary' ,
1725
+ 'Extended Summary' ,
1726
+ 'Parameters' ,
1727
+ 'Returns' ,
1728
+ 'Yields' ,
1729
+ 'Raises' ,
1730
+ 'Other Parameters' ,
1731
+ 'See Also' ,
1732
+ 'Notes' ,
1733
+ 'References' ,
1734
+ 'Examples' ]
1735
+
1736
+ if not docstring :
1737
+ return
1738
+
1739
+ ds = DocstringStream (docstring )
1740
+ if ds .line_number < 2 :
1741
+ return
1742
+
1743
+ _ = ds .consume_line () # Skipping the first line
1744
+ curr_line = ds .consume_line ()
1745
+
1746
+ while curr_line is not None :
1747
+ for section in SECTIONS :
1748
+ if section .lower () == curr_line .strip ().lower ():
1749
+ if len (curr_line ) > len (curr_line .lstrip ()):
1750
+ return D208 ()
1751
+ if section not in curr_line :
1752
+ return D404 (section , curr_line .strip ())
1753
+
1754
+ curr_line = ds .consume_line ()
1755
+ if curr_line .rstrip () != "-" * len (section ):
1756
+ return D405 (section , len (section ),
1757
+ len (curr_line .rstrip ()))
1758
+ curr_line = ds .consume_line ()
1759
+
1760
+
1761
+ class DocstringStream (object ):
1762
+ """Reads numpy conventions."""
1763
+
1764
+ def __init__ (self , docstring ):
1765
+ self ._lines = ast .literal_eval (docstring ).split ('\n ' )
1766
+ self ._base_indent = self ._find_indent_level (docstring )
1767
+ self ._line_index = 0
1768
+
1769
+ self ._handlers = {'parameters' : self ._consume_parameters_section }
1770
+ self .line_number = len (self ._lines )
1771
+
1772
+ def consume_line (self ):
1773
+ if self ._line_index >= len (self ._lines ):
1774
+ return None
1775
+ try :
1776
+ return self .peek_current_line ()
1777
+ finally :
1778
+ self ._line_index += 1
1779
+
1780
+ def peek_current_line (self ):
1781
+ # First line is not indented
1782
+ if self ._line_index == 0 :
1783
+ return self ._lines [self ._line_index ]
1784
+
1785
+ return self ._lines [self ._line_index ][self ._base_indent :]
1786
+
1787
+ def peek_next_line (self ):
1788
+ if self ._line_index + 1 >= self .line_number :
1789
+ return None
1790
+
1791
+ return self ._lines [self ._line_index + 1 ][self ._base_indent :]
1792
+
1793
+ def _verify_section_header (self , section_name ):
1794
+ curr_line = self .peek_current_line ()
1795
+
1796
+ def _consume_parameters_section (self ):
1797
+ pass
1798
+
1799
+
1800
+ @staticmethod
1801
+ def _find_indent_level (docstring ):
1802
+ lines = docstring .split ('\n ' )
1803
+ if len (lines ) > 1 :
1804
+ last_line = lines [- 1 ]
1805
+ if last_line .endswith ('"""' ):
1806
+ return last_line .find ('"""' )
1807
+ else :
1808
+ return last_line .find ("'''" )
1809
+ return 0
1810
+
1714
1811
1715
1812
def main (use_pep257 = False ):
1716
1813
try :
@@ -1722,6 +1819,12 @@ def main(use_pep257=False):
1722
1819
def main_pep257 ():
1723
1820
main (use_pep257 = True )
1724
1821
1822
+ def foo ():
1823
+ """A.
1824
+
1825
+ Parameters
1826
+ ---------
1827
+ """
1725
1828
1726
1829
if __name__ == '__main__' :
1727
1830
main ()
0 commit comments