1
1
#!/usr/bin/env python3
2
2
"""Check proposed changes for common issues."""
3
- import re
4
3
import sys
5
- import shutil
6
4
import os .path
7
5
import subprocess
8
6
import sysconfig
9
7
10
- import reindent
11
- import untabify
12
-
13
-
14
- # Excluded directories which are copies of external libraries:
15
- # don't check their coding style
16
- EXCLUDE_DIRS = [
17
- os .path .join ('Modules' , '_decimal' , 'libmpdec' ),
18
- os .path .join ('Modules' , 'expat' ),
19
- os .path .join ('Modules' , 'zlib' ),
20
- ]
21
8
SRCDIR = sysconfig .get_config_var ('srcdir' )
22
9
23
10
@@ -147,85 +134,11 @@ def changed_files(base_branch=None):
147
134
else :
148
135
sys .exit ('need a git checkout to get modified files' )
149
136
150
- filenames2 = []
151
- for filename in filenames :
152
- # Normalize the path to be able to match using .startswith()
153
- filename = os .path .normpath (filename )
154
- if any (filename .startswith (path ) for path in EXCLUDE_DIRS ):
155
- # Exclude the file
156
- continue
157
- filenames2 .append (filename )
158
-
137
+ # Normalize the path to be able to match using .startswith()
138
+ filenames2 = list (map (os .path .normpath , filenames ))
159
139
return filenames2
160
140
161
141
162
- def report_modified_files (file_paths ):
163
- count = len (file_paths )
164
- if count == 0 :
165
- return n_files_str (count )
166
- else :
167
- lines = ["{}:" .format (n_files_str (count ))]
168
- for path in file_paths :
169
- lines .append (" {}" .format (path ))
170
- return "\n " .join (lines )
171
-
172
-
173
- #: Python files that have tabs by design:
174
- _PYTHON_FILES_WITH_TABS = frozenset ({
175
- 'Tools/c-analyzer/cpython/_parser.py' ,
176
- })
177
-
178
-
179
- @status ("Fixing Python file whitespace" , info = report_modified_files )
180
- def normalize_whitespace (file_paths ):
181
- """Make sure that the whitespace for .py files have been normalized."""
182
- reindent .makebackup = False # No need to create backups.
183
- fixed = [
184
- path for path in file_paths
185
- if (
186
- path .endswith ('.py' )
187
- and path not in _PYTHON_FILES_WITH_TABS
188
- and reindent .check (os .path .join (SRCDIR , path ))
189
- )
190
- ]
191
- return fixed
192
-
193
-
194
- @status ("Fixing C file whitespace" , info = report_modified_files )
195
- def normalize_c_whitespace (file_paths ):
196
- """Report if any C files """
197
- fixed = []
198
- for path in file_paths :
199
- abspath = os .path .join (SRCDIR , path )
200
- with open (abspath , 'r' ) as f :
201
- if '\t ' not in f .read ():
202
- continue
203
- untabify .process (abspath , 8 , verbose = False )
204
- fixed .append (path )
205
- return fixed
206
-
207
-
208
- ws_re = re .compile (br'\s+(\r?\n)$' )
209
-
210
- @status ("Fixing docs whitespace" , info = report_modified_files )
211
- def normalize_docs_whitespace (file_paths ):
212
- fixed = []
213
- for path in file_paths :
214
- abspath = os .path .join (SRCDIR , path )
215
- try :
216
- with open (abspath , 'rb' ) as f :
217
- lines = f .readlines ()
218
- new_lines = [ws_re .sub (br'\1' , line ) for line in lines ]
219
- if new_lines != lines :
220
- shutil .copyfile (abspath , abspath + '.bak' )
221
- with open (abspath , 'wb' ) as f :
222
- f .writelines (new_lines )
223
- fixed .append (path )
224
- except Exception as err :
225
- print ('Cannot fix %s: %s' % (path , err ))
226
- return fixed
227
-
228
-
229
142
@status ("Docs modified" , modal = True )
230
143
def docs_modified (file_paths ):
231
144
"""Report if any file in the Doc directory has been changed."""
@@ -244,6 +157,7 @@ def reported_news(file_paths):
244
157
return any (p .startswith (os .path .join ('Misc' , 'NEWS.d' , 'next' ))
245
158
for p in file_paths )
246
159
160
+
247
161
@status ("configure regenerated" , modal = True , info = str )
248
162
def regenerated_configure (file_paths ):
249
163
"""Check if configure has been regenerated."""
@@ -252,6 +166,7 @@ def regenerated_configure(file_paths):
252
166
else :
253
167
return "not needed"
254
168
169
+
255
170
@status ("pyconfig.h.in regenerated" , modal = True , info = str )
256
171
def regenerated_pyconfig_h_in (file_paths ):
257
172
"""Check if pyconfig.h.in has been regenerated."""
@@ -260,43 +175,15 @@ def regenerated_pyconfig_h_in(file_paths):
260
175
else :
261
176
return "not needed"
262
177
263
- def ci (pull_request ):
264
- if pull_request == 'false' :
265
- print ('Not a pull request; skipping' )
266
- return
267
- base_branch = get_base_branch ()
268
- file_paths = changed_files (base_branch )
269
- python_files = [fn for fn in file_paths if fn .endswith ('.py' )]
270
- c_files = [fn for fn in file_paths if fn .endswith (('.c' , '.h' ))]
271
- doc_files = [fn for fn in file_paths if fn .startswith ('Doc' ) and
272
- fn .endswith (('.rst' , '.inc' ))]
273
- fixed = []
274
- fixed .extend (normalize_whitespace (python_files ))
275
- fixed .extend (normalize_c_whitespace (c_files ))
276
- fixed .extend (normalize_docs_whitespace (doc_files ))
277
- if not fixed :
278
- print ('No whitespace issues found' )
279
- else :
280
- print (f'Please fix the { len (fixed )} file(s) with whitespace issues' )
281
- print ('(on UNIX you can run `make patchcheck` to make the fixes)' )
282
- sys .exit (1 )
283
178
284
179
def main ():
285
180
base_branch = get_base_branch ()
286
181
file_paths = changed_files (base_branch )
287
- python_files = [fn for fn in file_paths if fn .endswith ('.py' )]
288
- c_files = [fn for fn in file_paths if fn .endswith (('.c' , '.h' ))]
289
- doc_files = [fn for fn in file_paths if fn .startswith ('Doc' ) and
290
- fn .endswith (('.rst' , '.inc' ))]
182
+ has_doc_files = any (fn for fn in file_paths if fn .startswith ('Doc' ) and
183
+ fn .endswith (('.rst' , '.inc' )))
291
184
misc_files = {p for p in file_paths if p .startswith ('Misc' )}
292
- # PEP 8 whitespace rules enforcement.
293
- normalize_whitespace (python_files )
294
- # C rules enforcement.
295
- normalize_c_whitespace (c_files )
296
- # Doc whitespace enforcement.
297
- normalize_docs_whitespace (doc_files )
298
185
# Docs updated.
299
- docs_modified (doc_files )
186
+ docs_modified (has_doc_files )
300
187
# Misc/ACKS changed.
301
188
credit_given (misc_files )
302
189
# Misc/NEWS changed.
@@ -307,19 +194,14 @@ def main():
307
194
regenerated_pyconfig_h_in (file_paths )
308
195
309
196
# Test suite run and passed.
310
- if python_files or c_files :
311
- end = " and check for refleaks?" if c_files else "?"
312
- print ()
313
- print ("Did you run the test suite" + end )
197
+ has_c_files = any (fn for fn in file_paths if fn .endswith (('.c' , '.h' )))
198
+ has_python_files = any (fn for fn in file_paths if fn .endswith ('.py' ))
199
+ print ()
200
+ if has_c_files :
201
+ print ("Did you run the test suite and check for refleaks?" )
202
+ elif has_python_files :
203
+ print ("Did you run the test suite?" )
314
204
315
205
316
206
if __name__ == '__main__' :
317
- import argparse
318
- parser = argparse .ArgumentParser (description = __doc__ )
319
- parser .add_argument ('--ci' ,
320
- help = 'Perform pass/fail checks' )
321
- args = parser .parse_args ()
322
- if args .ci :
323
- ci (args .ci )
324
- else :
325
- main ()
207
+ main ()
0 commit comments