@@ -96,9 +96,9 @@ class Value(object):
96
96
97
97
def __init__ (self , * args ):
98
98
if len (self ._fields ) != len (args ):
99
- raise ValueError ('got %s arguments for %s fields for %s: %s '
100
- % (len (args ), len (self ._fields ),
101
- self .__class__ .__name__ , self ._fields ))
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 ))
102
102
vars (self ).update (zip (self ._fields , args ))
103
103
104
104
def __hash__ (self ):
@@ -116,7 +116,7 @@ def __repr__(self):
116
116
class Definition (Value ):
117
117
118
118
_fields = ('name' , '_source' , 'start' , 'end' , 'decorators' , 'docstring' ,
119
- 'children' , 'parent' , 'skips ' )
119
+ 'children' , 'parent' , 'skipped_error_codes ' )
120
120
121
121
_human = property (lambda self : humanize (type (self ).__name__ ))
122
122
kind = property (lambda self : self ._human .split ()[- 1 ])
@@ -145,15 +145,16 @@ def is_empty_or_comment(line):
145
145
146
146
def __str__ (self ):
147
147
out = 'in %s %s `%s`' % (self ._publicity , self ._human , self .name )
148
- if self .skips :
149
- out += ' (skipping %s)' % self .skips
148
+ if self .skipped_error_codes :
149
+ out += ' (skipping {0})' . format ( self .skipped_error_codes )
150
150
return out
151
151
152
152
153
153
class Module (Definition ):
154
154
155
155
_fields = ('name' , '_source' , 'start' , 'end' , 'decorators' , 'docstring' ,
156
- 'children' , 'parent' , '_all' , 'future_imports' , 'skips' )
156
+ 'children' , 'parent' , '_all' , 'future_imports' ,
157
+ 'skipped_error_codes' )
157
158
is_public = True
158
159
_nest = staticmethod (lambda s : {'def' : Function , 'class' : Class }[s ])
159
160
module = property (lambda self : self )
@@ -469,13 +470,8 @@ def parse_definition(self, class_):
469
470
self .leapfrog (tk .OP , value = ":" )
470
471
else :
471
472
self .consume (tk .OP )
472
- skips = ''
473
473
if self .current .kind in (tk .NEWLINE , tk .COMMENT ):
474
- if self .current .kind == tk .COMMENT :
475
- if 'noqa: ' in self .current .value :
476
- skips = '' .join (self .current .value .split ('noqa: ' )[1 :])
477
- elif self .current .value .startswith ('# noqa' ):
478
- skips = 'all'
474
+ skipped_error_codes = self .parse_skip_comment ()
479
475
self .leapfrog (tk .INDENT )
480
476
assert self .current .kind != tk .INDENT
481
477
docstring = self .parse_docstring ()
@@ -486,20 +482,33 @@ def parse_definition(self, class_):
486
482
log .debug ("finished parsing nested definitions for '%s'" , name )
487
483
end = self .line - 1
488
484
else : # one-liner definition
485
+ skipped_error_codes = ''
489
486
docstring = self .parse_docstring ()
490
487
decorators = [] # TODO
491
488
children = []
492
489
end = self .line
493
490
self .leapfrog (tk .NEWLINE )
494
491
definition = class_ (name , self .source , start , end ,
495
- decorators , docstring , children , None , skips )
492
+ decorators , docstring , children , None ,
493
+ skipped_error_codes )
496
494
for child in definition .children :
497
495
child .parent = definition
498
496
log .debug ("finished parsing %s '%s'. Next token is %r (%s)" ,
499
497
class_ .__name__ , name , self .current .kind ,
500
498
self .current .value )
501
499
return definition
502
500
501
+ def parse_skip_comment (self ):
502
+ """Parse a definition comment for noqa skips."""
503
+ skipped_error_codes = ''
504
+ if self .current .kind == tk .COMMENT :
505
+ if 'noqa: ' in self .current .value :
506
+ skipped_error_codes = '' .join (
507
+ self .current .value .split ('noqa: ' )[1 :])
508
+ elif self .current .value .startswith ('# noqa' ):
509
+ skipped_error_codes = 'all'
510
+ return skipped_error_codes
511
+
503
512
def check_current (self , kind = None , value = None ):
504
513
msg = textwrap .dedent ("""
505
514
Unexpected token at line {self.line}:
@@ -1413,13 +1422,14 @@ def check_source(self, source, filename):
1413
1422
for check in self .checks :
1414
1423
terminate = False
1415
1424
if isinstance (definition , check ._check_for ):
1416
- if definition .skips != 'all' :
1425
+ if definition .skipped_error_codes != 'all' :
1417
1426
error = check (None , definition , definition .docstring )
1418
1427
else :
1419
1428
error = None
1420
1429
errors = error if hasattr (error , '__iter__' ) else [error ]
1421
1430
for error in errors :
1422
- if error is not None :
1431
+ if error is not None and error .code not in \
1432
+ definition .skipped_error_codes :
1423
1433
partition = check .__doc__ .partition ('.\n ' )
1424
1434
message , _ , explanation = partition
1425
1435
error .set_context (explanation = explanation ,
@@ -1457,10 +1467,7 @@ def check_docstring_missing(self, definition, docstring):
1457
1467
Method : (lambda : D105 () if is_magic (definition .name )
1458
1468
else D102 ()),
1459
1469
Function : D103 , NestedFunction : D103 , Package : D104 }
1460
- code = codes [type (definition )]
1461
- if code .__name__ in definition .skips :
1462
- return
1463
- return code ()
1470
+ return codes [type (definition )]()
1464
1471
1465
1472
@check_for (Definition )
1466
1473
def check_one_liners (self , definition , docstring ):
@@ -1470,8 +1477,6 @@ def check_one_liners(self, definition, docstring):
1470
1477
This looks better for one-liners.
1471
1478
1472
1479
"""
1473
- if 'D200' in definition .skips :
1474
- return
1475
1480
if docstring :
1476
1481
lines = ast .literal_eval (docstring ).split ('\n ' )
1477
1482
if len (lines ) > 1 :
@@ -1493,11 +1498,9 @@ def check_no_blank_before(self, function, docstring): # def
1493
1498
blanks_before_count = sum (takewhile (bool , reversed (blanks_before )))
1494
1499
blanks_after_count = sum (takewhile (bool , blanks_after ))
1495
1500
if blanks_before_count != 0 :
1496
- if 'D201' not in function .skips :
1497
- yield D201 (blanks_before_count )
1501
+ yield D201 (blanks_before_count )
1498
1502
if not all (blanks_after ) and blanks_after_count != 0 :
1499
- if 'D202' not in function .skips :
1500
- yield D202 (blanks_after_count )
1503
+ yield D202 (blanks_after_count )
1501
1504
1502
1505
@check_for (Class )
1503
1506
def check_blank_before_after_class (self , class_ , docstring ):
@@ -1525,12 +1528,11 @@ def check_blank_before_after_class(self, class_, docstring):
1525
1528
blanks_after = list (map (is_blank , after .split ('\n ' )[1 :]))
1526
1529
blanks_before_count = sum (takewhile (bool , reversed (blanks_before )))
1527
1530
blanks_after_count = sum (takewhile (bool , blanks_after ))
1528
- if 'D211' not in class_ . skips and blanks_before_count != 0 :
1531
+ if blanks_before_count != 0 :
1529
1532
yield D211 (blanks_before_count )
1530
- if 'D203' not in class_ . skips and blanks_before_count != 1 :
1533
+ if blanks_before_count != 1 :
1531
1534
yield D203 (blanks_before_count )
1532
- if 'D204' not in class_ .skips and (not all (blanks_after ) and
1533
- blanks_after_count != 1 ):
1535
+ if not all (blanks_after ) and blanks_after_count != 1 :
1534
1536
yield D204 (blanks_after_count )
1535
1537
1536
1538
@check_for (Definition )
@@ -1545,8 +1547,6 @@ def check_blank_after_summary(self, definition, docstring):
1545
1547
1546
1548
"""
1547
1549
if docstring :
1548
- if 'D205' in definition .skips :
1549
- return
1550
1550
lines = ast .literal_eval (docstring ).strip ().split ('\n ' )
1551
1551
if len (lines ) > 1 :
1552
1552
post_summary_blanks = list (map (is_blank , lines [1 :]))
@@ -1569,16 +1569,13 @@ def check_indent(self, definition, docstring):
1569
1569
if len (lines ) > 1 :
1570
1570
lines = lines [1 :] # First line does not need indent.
1571
1571
indents = [leading_space (l ) for l in lines if not is_blank (l )]
1572
- if 'D206' not in definition .skips :
1573
- if set (' \t ' ) == set ('' .join (indents ) + indent ):
1574
- yield D206 ()
1575
- if 'D208' not in definition .skips :
1576
- if (len (indents ) > 1 and min (indents [:- 1 ]) > indent or
1577
- indents [- 1 ] > indent ):
1578
- yield D208 ()
1579
- if 'D207' not in definition .skips :
1580
- if min (indents ) < indent :
1581
- yield D207 ()
1572
+ if set (' \t ' ) == set ('' .join (indents ) + indent ):
1573
+ yield D206 ()
1574
+ if (len (indents ) > 1 and min (indents [:- 1 ]) > indent or
1575
+ indents [- 1 ] > indent ):
1576
+ yield D208 ()
1577
+ if min (indents ) < indent :
1578
+ yield D207 ()
1582
1579
1583
1580
@check_for (Definition )
1584
1581
def check_newline_after_last_paragraph (self , definition , docstring ):
@@ -1588,7 +1585,7 @@ def check_newline_after_last_paragraph(self, definition, docstring):
1588
1585
quotes on a line by themselves.
1589
1586
1590
1587
"""
1591
- if docstring and 'D209' not in definition . skips :
1588
+ if docstring :
1592
1589
lines = [l for l in ast .literal_eval (docstring ).split ('\n ' )
1593
1590
if not is_blank (l )]
1594
1591
if len (lines ) > 1 :
@@ -1598,7 +1595,7 @@ def check_newline_after_last_paragraph(self, definition, docstring):
1598
1595
@check_for (Definition )
1599
1596
def check_surrounding_whitespaces (self , definition , docstring ):
1600
1597
"""D210: No whitespaces allowed surrounding docstring text."""
1601
- if docstring and 'D210' not in definition . skips :
1598
+ if docstring :
1602
1599
lines = ast .literal_eval (docstring ).split ('\n ' )
1603
1600
if lines [0 ].startswith (' ' ) or \
1604
1601
len (lines ) == 1 and lines [0 ].endswith (' ' ):
@@ -1624,11 +1621,9 @@ def check_multi_line_summary_start(self, definition, docstring):
1624
1621
if len (lines ) > 1 :
1625
1622
first = docstring .split ("\n " )[0 ].strip ().lower ()
1626
1623
if first in start_triple :
1627
- if 'D212' not in definition .skips :
1628
- return D212 ()
1624
+ return D212 ()
1629
1625
else :
1630
- if 'D213' not in definition .skips :
1631
- return D213 ()
1626
+ return D213 ()
1632
1627
1633
1628
@check_for (Definition )
1634
1629
def check_triple_double_quotes (self , definition , docstring ):
@@ -1643,7 +1638,7 @@ def check_triple_double_quotes(self, definition, docstring):
1643
1638
""" quotes in its body.
1644
1639
1645
1640
'''
1646
- if docstring and 'D300' not in definition . skips :
1641
+ if docstring :
1647
1642
opening = docstring [:5 ].lower ()
1648
1643
if '"""' in ast .literal_eval (docstring ) and opening .startswith (
1649
1644
("'''" , "r'''" , "u'''" , "ur'''" )):
@@ -1665,8 +1660,8 @@ def check_backslashes(self, definition, docstring):
1665
1660
'''
1666
1661
# Just check that docstring is raw, check_triple_double_quotes
1667
1662
# ensures the correct quotes.
1668
- if docstring and 'D301' not in definition . skips and \
1669
- ' \\ ' in docstring and not docstring . startswith ( ('r' , 'ur' )):
1663
+ if docstring and '\\ ' in docstring and not docstring . startswith (
1664
+ ('r' , 'ur' )):
1670
1665
return D301 ()
1671
1666
1672
1667
@check_for (Definition )
@@ -1681,8 +1676,7 @@ def check_unicode_docstring(self, definition, docstring):
1681
1676
1682
1677
# Just check that docstring is unicode, check_triple_double_quotes
1683
1678
# ensures the correct quotes.
1684
- if docstring and sys .version_info [0 ] <= 2 and \
1685
- 'D302' not in definition .skips :
1679
+ if docstring and sys .version_info [0 ] <= 2 :
1686
1680
if not is_ascii (docstring ) and not docstring .startswith (
1687
1681
('u' , 'ur' )):
1688
1682
return D302 ()
@@ -1694,7 +1688,7 @@ def check_ends_with_period(self, definition, docstring):
1694
1688
The [first line of a] docstring is a phrase ending in a period.
1695
1689
1696
1690
"""
1697
- if docstring and 'D400' not in definition . skips :
1691
+ if docstring :
1698
1692
summary_line = ast .literal_eval (docstring ).strip ().split ('\n ' )[0 ]
1699
1693
if not summary_line .endswith ('.' ):
1700
1694
return D400 (summary_line [- 1 ])
@@ -1708,7 +1702,7 @@ def check_imperative_mood(self, function, docstring): # def context
1708
1702
"Returns the pathname ...".
1709
1703
1710
1704
"""
1711
- if docstring and 'D401' not in function . skips :
1705
+ if docstring :
1712
1706
stripped = ast .literal_eval (docstring ).strip ()
1713
1707
if stripped :
1714
1708
first_word = stripped .split ()[0 ]
@@ -1723,7 +1717,7 @@ def check_no_signature(self, function, docstring): # def context
1723
1717
function/method parameters (which can be obtained by introspection).
1724
1718
1725
1719
"""
1726
- if docstring and 'D402' not in function . skips :
1720
+ if docstring :
1727
1721
first_line = ast .literal_eval (docstring ).strip ().split ('\n ' )[0 ]
1728
1722
if function .name + '(' in first_line .replace (' ' , '' ):
1729
1723
return D402 ()
@@ -1735,7 +1729,7 @@ def check_capitalized(self, function, docstring):
1735
1729
The [first line of a] docstring is a phrase ending in a period.
1736
1730
1737
1731
"""
1738
- if docstring and 'D403' not in function . skips :
1732
+ if docstring :
1739
1733
first_word = ast .literal_eval (docstring ).split ()[0 ]
1740
1734
if first_word == first_word .upper ():
1741
1735
return
@@ -1753,7 +1747,7 @@ def check_starts_with_this(self, function, docstring):
1753
1747
with "This class is [..]" or "This module contains [..]".
1754
1748
1755
1749
"""
1756
- if docstring and 'D404' not in function . skips :
1750
+ if docstring :
1757
1751
first_word = ast .literal_eval (docstring ).split ()[0 ]
1758
1752
if first_word .lower () == 'this' :
1759
1753
return D404 ()
0 commit comments