Skip to content

Commit c9157fe

Browse files
authored
[3.12] GH-109408: Move the C file whitespace check from patchcheck to pre-commit (GH-109890) (#110636)
(cherry picked from commit f5edb56)
1 parent 9485765 commit c9157fe

File tree

3 files changed

+23
-90
lines changed

3 files changed

+23
-90
lines changed

.pre-commit-config.yaml

+15
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,21 @@ repos:
3232
types: [python]
3333
exclude: '^(Lib/test/tokenizedata/|Tools/c-analyzer/cpython/_parser).*$'
3434

35+
- repo: local
36+
hooks:
37+
- id: c-file-whitespace
38+
name: "Check C file whitespace"
39+
entry: "python Tools/patchcheck/untabify.py"
40+
language: "system"
41+
types_or: ['c', 'c++']
42+
# Don't check the style of vendored libraries
43+
exclude: |
44+
(?x)^(
45+
Modules/_decimal/.*
46+
| Modules/libmpdec/.*
47+
| Modules/expat/.*
48+
)$
49+
3550
- repo: https://github.com/sphinx-contrib/sphinx-lint
3651
rev: v0.6.8
3752
hooks:

Tools/patchcheck/patchcheck.py

+3-85
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,15 @@
11
#!/usr/bin/env python3
22
"""Check proposed changes for common issues."""
3-
import re
43
import sys
5-
import shutil
64
import os.path
75
import subprocess
86
import sysconfig
97

10-
import untabify
11-
12-
138
def get_python_source_dir():
149
src_dir = sysconfig.get_config_var('abs_srcdir')
1510
if not src_dir:
1611
src_dir = sysconfig.get_config_var('srcdir')
1712
return os.path.abspath(src_dir)
18-
19-
20-
# Excluded directories which are copies of external libraries:
21-
# don't check their coding style
22-
EXCLUDE_DIRS = [
23-
os.path.join('Modules', '_decimal', 'libmpdec'),
24-
os.path.join('Modules', 'expat'),
25-
os.path.join('Modules', 'zlib'),
26-
]
2713
SRCDIR = get_python_source_dir()
2814

2915

@@ -154,47 +140,8 @@ def changed_files(base_branch=None):
154140
else:
155141
sys.exit('need a git checkout to get modified files')
156142

157-
filenames2 = []
158-
for filename in filenames:
159-
# Normalize the path to be able to match using .startswith()
160-
filename = os.path.normpath(filename)
161-
if any(filename.startswith(path) for path in EXCLUDE_DIRS):
162-
# Exclude the file
163-
continue
164-
filenames2.append(filename)
165-
166-
return filenames2
167-
168-
169-
def report_modified_files(file_paths):
170-
count = len(file_paths)
171-
if count == 0:
172-
return n_files_str(count)
173-
else:
174-
lines = [f"{n_files_str(count)}:"]
175-
for path in file_paths:
176-
lines.append(f" {path}")
177-
return "\n".join(lines)
178-
179-
180-
#: Python files that have tabs by design:
181-
_PYTHON_FILES_WITH_TABS = frozenset({
182-
'Tools/c-analyzer/cpython/_parser.py',
183-
})
184-
185-
186-
@status("Fixing C file whitespace", info=report_modified_files)
187-
def normalize_c_whitespace(file_paths):
188-
"""Report if any C files """
189-
fixed = []
190-
for path in file_paths:
191-
abspath = os.path.join(SRCDIR, path)
192-
with open(abspath, 'r') as f:
193-
if '\t' not in f.read():
194-
continue
195-
untabify.process(abspath, 8, verbose=False)
196-
fixed.append(path)
197-
return fixed
143+
# Normalize the path to be able to match using str.startswith()
144+
return list(map(os.path.normpath, filenames))
198145

199146

200147
@status("Docs modified", modal=True)
@@ -234,33 +181,12 @@ def regenerated_pyconfig_h_in(file_paths):
234181
return "not needed"
235182

236183

237-
def ci(pull_request):
238-
if pull_request == 'false':
239-
print('Not a pull request; skipping')
240-
return
241-
base_branch = get_base_branch()
242-
file_paths = changed_files(base_branch)
243-
c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))]
244-
fixed = []
245-
fixed.extend(normalize_c_whitespace(c_files))
246-
if not fixed:
247-
print('No whitespace issues found')
248-
else:
249-
count = len(fixed)
250-
print(f'Please fix the {n_files_str(count)} with whitespace issues')
251-
print('(on Unix you can run `make patchcheck` to make the fixes)')
252-
sys.exit(1)
253-
254-
255184
def main():
256185
base_branch = get_base_branch()
257186
file_paths = changed_files(base_branch)
258-
c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))]
259187
doc_files = [fn for fn in file_paths if fn.startswith('Doc') and
260188
fn.endswith(('.rst', '.inc'))]
261189
misc_files = {p for p in file_paths if p.startswith('Misc')}
262-
# C rules enforcement.
263-
normalize_c_whitespace(c_files)
264190
# Docs updated.
265191
docs_modified(doc_files)
266192
# Misc/ACKS changed.
@@ -283,12 +209,4 @@ def main():
283209

284210

285211
if __name__ == '__main__':
286-
import argparse
287-
parser = argparse.ArgumentParser(description=__doc__)
288-
parser.add_argument('--ci',
289-
help='Perform pass/fail checks')
290-
args = parser.parse_args()
291-
if args.ci:
292-
ci(args.ci)
293-
else:
294-
main()
212+
main()

Tools/patchcheck/untabify.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ def main():
2121
if optname == '-t':
2222
tabsize = int(optvalue)
2323

24-
for filename in args:
25-
process(filename, tabsize)
24+
return max(process(filename, tabsize) for filename in args)
2625

2726

2827
def process(filename, tabsize, verbose=True):
@@ -32,10 +31,10 @@ def process(filename, tabsize, verbose=True):
3231
encoding = f.encoding
3332
except IOError as msg:
3433
print("%r: I/O error: %s" % (filename, msg))
35-
return
34+
return 2
3635
newtext = text.expandtabs(tabsize)
3736
if newtext == text:
38-
return
37+
return 0
3938
backup = filename + "~"
4039
try:
4140
os.unlink(backup)
@@ -49,7 +48,8 @@ def process(filename, tabsize, verbose=True):
4948
f.write(newtext)
5049
if verbose:
5150
print(filename)
51+
return 1
5252

5353

5454
if __name__ == '__main__':
55-
main()
55+
raise SystemExit(main())

0 commit comments

Comments
 (0)