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