|
8 | 8 |
|
9 | 9 | whitespace_rules = [
|
10 | 10 | # This linter should be first since bash_rules depends on it.
|
11 |
| - {'pattern': r'\s+$', |
12 |
| - 'strip': '\n', |
13 |
| - 'description': 'Fix trailing whitespace'}, |
14 |
| - {'pattern': '\t', |
15 |
| - 'strip': '\n', |
16 |
| - 'description': 'Fix tab-based whitespace'}, |
| 11 | + {'pattern': r'\s+$', 'strip': '\n', 'description': 'Fix trailing whitespace'}, |
| 12 | + {'pattern': '\t', 'strip': '\n', 'description': 'Fix tab-based whitespace'}, |
17 | 13 | ] # type: List[Rule]
|
18 | 14 |
|
19 |
| -markdown_whitespace_rules = list([rule for rule in whitespace_rules if rule['pattern'] != r'\s+$']) + [ |
| 15 | +markdown_whitespace_rules = list( |
| 16 | + [rule for rule in whitespace_rules if rule['pattern'] != r'\s+$'] |
| 17 | +) + [ |
20 | 18 | # Two spaces trailing a line with other content is okay--it's a markdown line break.
|
21 | 19 | # This rule finds one space trailing a non-space, three or more trailing spaces, and
|
22 | 20 | # spaces on an empty line.
|
23 |
| - {'pattern': r'((?<!\s)\s$)|(\s\s\s+$)|(^\s+$)', |
24 |
| - 'strip': '\n', |
25 |
| - 'description': 'Fix trailing whitespace'}, |
26 |
| - {'pattern': r'^#+[A-Za-z0-9]', |
27 |
| - 'strip': '\n', |
28 |
| - 'description': 'Missing space after # in heading'}, |
| 21 | + { |
| 22 | + 'pattern': r'((?<!\s)\s$)|(\s\s\s+$)|(^\s+$)', |
| 23 | + 'strip': '\n', |
| 24 | + 'description': 'Fix trailing whitespace', |
| 25 | + }, |
| 26 | + { |
| 27 | + 'pattern': r'^#+[A-Za-z0-9]', |
| 28 | + 'strip': '\n', |
| 29 | + 'description': 'Missing space after # in heading', |
| 30 | + }, |
29 | 31 | ]
|
30 | 32 |
|
31 | 33 | python_rules = RuleList(
|
32 | 34 | langs=['py'],
|
33 | 35 | rules=[
|
34 |
| - {'pattern': r'".*"%\([a-z_].*\)?$', |
35 |
| - 'description': 'Missing space around "%"'}, |
36 |
| - {'pattern': r"'.*'%\([a-z_].*\)?$", |
37 |
| - 'description': 'Missing space around "%"'}, |
| 36 | + {'pattern': r'".*"%\([a-z_].*\)?$', 'description': 'Missing space around "%"'}, |
| 37 | + {'pattern': r"'.*'%\([a-z_].*\)?$", 'description': 'Missing space around "%"'}, |
38 | 38 | # This rule is constructed with + to avoid triggering on itself
|
39 |
| - {'pattern': r" =" + r'[^ =>~"]', |
40 |
| - 'description': 'Missing whitespace after "="'}, |
41 |
| - {'pattern': r'":\w[^"]*$', |
42 |
| - 'description': 'Missing whitespace after ":"'}, |
43 |
| - {'pattern': r"':\w[^']*$", |
44 |
| - 'description': 'Missing whitespace after ":"'}, |
45 |
| - {'pattern': r"^\s+[#]\w", |
46 |
| - 'strip': '\n', |
47 |
| - 'description': 'Missing whitespace after "#"'}, |
48 |
| - {'pattern': r"assertEquals[(]", |
49 |
| - 'description': 'Use assertEqual, not assertEquals (which is deprecated).'}, |
50 |
| - {'pattern': r'self: Any', |
51 |
| - 'description': 'you can omit Any annotation for self', |
52 |
| - 'good_lines': ['def foo (self):'], |
53 |
| - 'bad_lines': ['def foo(self: Any):']}, |
54 |
| - {'pattern': r"== None", |
55 |
| - 'description': 'Use `is None` to check whether something is None'}, |
56 |
| - {'pattern': r"type:[(]", |
57 |
| - 'description': 'Missing whitespace after ":" in type annotation'}, |
58 |
| - {'pattern': r"# type [(]", |
59 |
| - 'description': 'Missing : after type in type annotation'}, |
60 |
| - {'pattern': r"#type", |
61 |
| - 'description': 'Missing whitespace after "#" in type annotation'}, |
62 |
| - {'pattern': r'if[(]', |
63 |
| - 'description': 'Missing space between if and ('}, |
64 |
| - {'pattern': r", [)]", |
65 |
| - 'description': 'Unnecessary whitespace between "," and ")"'}, |
66 |
| - {'pattern': r"% [(]", |
67 |
| - 'description': 'Unnecessary whitespace between "%" and "("'}, |
| 39 | + {'pattern': r" =" + r'[^ =>~"]', 'description': 'Missing whitespace after "="'}, |
| 40 | + {'pattern': r'":\w[^"]*$', 'description': 'Missing whitespace after ":"'}, |
| 41 | + {'pattern': r"':\w[^']*$", 'description': 'Missing whitespace after ":"'}, |
| 42 | + {'pattern': r"^\s+[#]\w", 'strip': '\n', 'description': 'Missing whitespace after "#"'}, |
| 43 | + { |
| 44 | + 'pattern': r"assertEquals[(]", |
| 45 | + 'description': 'Use assertEqual, not assertEquals (which is deprecated).', |
| 46 | + }, |
| 47 | + { |
| 48 | + 'pattern': r'self: Any', |
| 49 | + 'description': 'you can omit Any annotation for self', |
| 50 | + 'good_lines': ['def foo (self):'], |
| 51 | + 'bad_lines': ['def foo(self: Any):'], |
| 52 | + }, |
| 53 | + {'pattern': r"== None", 'description': 'Use `is None` to check whether something is None'}, |
| 54 | + {'pattern': r"type:[(]", 'description': 'Missing whitespace after ":" in type annotation'}, |
| 55 | + {'pattern': r"# type [(]", 'description': 'Missing : after type in type annotation'}, |
| 56 | + {'pattern': r"#type", 'description': 'Missing whitespace after "#" in type annotation'}, |
| 57 | + {'pattern': r'if[(]', 'description': 'Missing space between if and ('}, |
| 58 | + {'pattern': r", [)]", 'description': 'Unnecessary whitespace between "," and ")"'}, |
| 59 | + {'pattern': r"% [(]", 'description': 'Unnecessary whitespace between "%" and "("'}, |
68 | 60 | # This next check could have false positives, but it seems pretty
|
69 | 61 | # rare; if we find any, they can be added to the exclude list for
|
70 | 62 | # this rule.
|
71 |
| - {'pattern': r' % [a-zA-Z0-9_.]*\)?$', |
72 |
| - 'description': 'Used % comprehension without a tuple'}, |
73 |
| - {'pattern': r'.*%s.* % \([a-zA-Z0-9_.]*\)$', |
74 |
| - 'description': 'Used % comprehension without a tuple'}, |
75 |
| - {'pattern': r'__future__', |
76 |
| - 'include_only': {'zulip_bots/zulip_bots/bots/'}, |
77 |
| - 'description': 'Bots no longer need __future__ imports.'}, |
78 |
| - {'pattern': r'#!/usr/bin/env python$', |
79 |
| - 'include_only': {'zulip_bots/'}, |
80 |
| - 'description': 'Python shebangs must be python3'}, |
81 |
| - {'pattern': r'(^|\s)open\s*\(', |
82 |
| - 'description': 'open() should not be used in Zulip\'s bots. Use functions' |
83 |
| - ' provided by the bots framework to access the filesystem.', |
84 |
| - 'include_only': {'zulip_bots/zulip_bots/bots/'}}, |
85 |
| - {'pattern': r'pprint', |
86 |
| - 'description': 'Used pprint, which is most likely a debugging leftover. For user output, use print().'}, |
87 |
| - {'pattern': r'\(BotTestCase\)', |
88 |
| - 'bad_lines': ['class TestSomeBot(BotTestCase):'], |
89 |
| - 'description': 'Bot test cases should directly inherit from BotTestCase *and* DefaultTests.'}, |
90 |
| - {'pattern': r'\(DefaultTests, BotTestCase\)', |
91 |
| - 'bad_lines': ['class TestSomeBot(DefaultTests, BotTestCase):'], |
92 |
| - 'good_lines': ['class TestSomeBot(BotTestCase, DefaultTests):'], |
93 |
| - 'description': 'Bot test cases should inherit from BotTestCase before DefaultTests.'}, |
| 63 | + { |
| 64 | + 'pattern': r' % [a-zA-Z0-9_.]*\)?$', |
| 65 | + 'description': 'Used % comprehension without a tuple', |
| 66 | + }, |
| 67 | + { |
| 68 | + 'pattern': r'.*%s.* % \([a-zA-Z0-9_.]*\)$', |
| 69 | + 'description': 'Used % comprehension without a tuple', |
| 70 | + }, |
| 71 | + { |
| 72 | + 'pattern': r'__future__', |
| 73 | + 'include_only': {'zulip_bots/zulip_bots/bots/'}, |
| 74 | + 'description': 'Bots no longer need __future__ imports.', |
| 75 | + }, |
| 76 | + { |
| 77 | + 'pattern': r'#!/usr/bin/env python$', |
| 78 | + 'include_only': {'zulip_bots/'}, |
| 79 | + 'description': 'Python shebangs must be python3', |
| 80 | + }, |
| 81 | + { |
| 82 | + 'pattern': r'(^|\s)open\s*\(', |
| 83 | + 'description': 'open() should not be used in Zulip\'s bots. Use functions' |
| 84 | + ' provided by the bots framework to access the filesystem.', |
| 85 | + 'include_only': {'zulip_bots/zulip_bots/bots/'}, |
| 86 | + }, |
| 87 | + { |
| 88 | + 'pattern': r'pprint', |
| 89 | + 'description': 'Used pprint, which is most likely a debugging leftover. For user output, use print().', |
| 90 | + }, |
| 91 | + { |
| 92 | + 'pattern': r'\(BotTestCase\)', |
| 93 | + 'bad_lines': ['class TestSomeBot(BotTestCase):'], |
| 94 | + 'description': 'Bot test cases should directly inherit from BotTestCase *and* DefaultTests.', |
| 95 | + }, |
| 96 | + { |
| 97 | + 'pattern': r'\(DefaultTests, BotTestCase\)', |
| 98 | + 'bad_lines': ['class TestSomeBot(DefaultTests, BotTestCase):'], |
| 99 | + 'good_lines': ['class TestSomeBot(BotTestCase, DefaultTests):'], |
| 100 | + 'description': 'Bot test cases should inherit from BotTestCase before DefaultTests.', |
| 101 | + }, |
94 | 102 | *whitespace_rules,
|
95 | 103 | ],
|
96 | 104 | max_length=140,
|
|
99 | 107 | bash_rules = RuleList(
|
100 | 108 | langs=['sh'],
|
101 | 109 | rules=[
|
102 |
| - {'pattern': r'#!.*sh [-xe]', |
103 |
| - 'description': 'Fix shebang line with proper call to /usr/bin/env for Bash path, change -x|-e switches' |
104 |
| - ' to set -x|set -e'}, |
| 110 | + { |
| 111 | + 'pattern': r'#!.*sh [-xe]', |
| 112 | + 'description': 'Fix shebang line with proper call to /usr/bin/env for Bash path, change -x|-e switches' |
| 113 | + ' to set -x|set -e', |
| 114 | + }, |
105 | 115 | *whitespace_rules[0:1],
|
106 | 116 | ],
|
107 | 117 | )
|
|
116 | 126 | # version of the tab-based whitespace rule (we can't just use
|
117 | 127 | # exclude in whitespace_rules, since we only want to ignore
|
118 | 128 | # JSON files with tab-based whitespace, not webhook code).
|
119 |
| - rules= whitespace_rules[0:1], |
| 129 | + rules=whitespace_rules[0:1], |
120 | 130 | )
|
121 | 131 |
|
122 | 132 | prose_style_rules = [
|
123 |
| - {'pattern': r'[^\/\#\-"]([jJ]avascript)', # exclude usage in hrefs/divs |
124 |
| - 'description': "javascript should be spelled JavaScript"}, |
125 |
| - {'pattern': r'''[^\/\-\."'\_\=\>]([gG]ithub)[^\.\-\_"\<]''', # exclude usage in hrefs/divs |
126 |
| - 'description': "github should be spelled GitHub"}, |
127 |
| - {'pattern': r'[oO]rganisation', # exclude usage in hrefs/divs |
128 |
| - 'description': "Organization is spelled with a z"}, |
129 |
| - {'pattern': r'!!! warning', |
130 |
| - 'description': "!!! warning is invalid; it's spelled '!!! warn'"}, |
131 |
| - {'pattern': r'[^-_]botserver(?!rc)|bot server', |
132 |
| - 'description': "Use Botserver instead of botserver or Botserver."}, |
| 133 | + { |
| 134 | + 'pattern': r'[^\/\#\-"]([jJ]avascript)', # exclude usage in hrefs/divs |
| 135 | + 'description': "javascript should be spelled JavaScript", |
| 136 | + }, |
| 137 | + { |
| 138 | + 'pattern': r'''[^\/\-\."'\_\=\>]([gG]ithub)[^\.\-\_"\<]''', # exclude usage in hrefs/divs |
| 139 | + 'description': "github should be spelled GitHub", |
| 140 | + }, |
| 141 | + { |
| 142 | + 'pattern': r'[oO]rganisation', # exclude usage in hrefs/divs |
| 143 | + 'description': "Organization is spelled with a z", |
| 144 | + }, |
| 145 | + {'pattern': r'!!! warning', 'description': "!!! warning is invalid; it's spelled '!!! warn'"}, |
| 146 | + { |
| 147 | + 'pattern': r'[^-_]botserver(?!rc)|bot server', |
| 148 | + 'description': "Use Botserver instead of botserver or Botserver.", |
| 149 | + }, |
133 | 150 | ] # type: List[Rule]
|
134 | 151 |
|
135 | 152 | markdown_docs_length_exclude = {
|
|
141 | 158 | rules=[
|
142 | 159 | *markdown_whitespace_rules,
|
143 | 160 | *prose_style_rules,
|
144 |
| - {'pattern': r'\[(?P<url>[^\]]+)\]\((?P=url)\)', |
145 |
| - 'description': 'Linkified markdown URLs should use cleaner <http://example.com> syntax.'} |
| 161 | + { |
| 162 | + 'pattern': r'\[(?P<url>[^\]]+)\]\((?P=url)\)', |
| 163 | + 'description': 'Linkified markdown URLs should use cleaner <http://example.com> syntax.', |
| 164 | + }, |
146 | 165 | ],
|
147 | 166 | max_length=120,
|
148 | 167 | length_exclude=markdown_docs_length_exclude,
|
|
0 commit comments