Skip to content

Commit de956b2

Browse files
authored
gh-109408: Revert pre-commit whitespace checks pending portable solution (#110726)
1 parent 467abfe commit de956b2

File tree

2 files changed

+110
-34
lines changed

2 files changed

+110
-34
lines changed

.pre-commit-config.yaml

-24
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,6 @@ repos:
2323
- id: trailing-whitespace
2424
types_or: [c, inc, python, rst]
2525

26-
- repo: local
27-
hooks:
28-
- id: python-file-whitespace
29-
name: "Check Python file whitespace"
30-
entry: 'python Tools/patchcheck/reindent.py --nobackup --newline LF'
31-
language: 'system'
32-
types: [python]
33-
exclude: '^(Lib/test/tokenizedata/|Tools/c-analyzer/cpython/_parser).*$'
34-
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-
5026
- repo: https://github.com/sphinx-contrib/sphinx-lint
5127
rev: v0.6.8
5228
hooks:

Tools/patchcheck/patchcheck.py

+110-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
11
#!/usr/bin/env python3
22
"""Check proposed changes for common issues."""
3+
import re
34
import sys
5+
import shutil
46
import os.path
57
import subprocess
68
import sysconfig
79

10+
import reindent
11+
import untabify
12+
13+
814
def get_python_source_dir():
915
src_dir = sysconfig.get_config_var('abs_srcdir')
1016
if not src_dir:
1117
src_dir = sysconfig.get_config_var('srcdir')
1218
return os.path.abspath(src_dir)
19+
20+
21+
# Excluded directories which are copies of external libraries:
22+
# don't check their coding style
23+
EXCLUDE_DIRS = [
24+
os.path.join('Modules', '_decimal', 'libmpdec'),
25+
os.path.join('Modules', 'expat'),
26+
os.path.join('Modules', 'zlib'),
27+
]
1328
SRCDIR = get_python_source_dir()
1429

1530

@@ -140,8 +155,62 @@ def changed_files(base_branch=None):
140155
else:
141156
sys.exit('need a git checkout to get modified files')
142157

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

146215

147216
@status("Docs modified", modal=True)
@@ -181,12 +250,38 @@ def regenerated_pyconfig_h_in(file_paths):
181250
return "not needed"
182251

183252

253+
def ci(pull_request):
254+
if pull_request == 'false':
255+
print('Not a pull request; skipping')
256+
return
257+
base_branch = get_base_branch()
258+
file_paths = changed_files(base_branch)
259+
python_files = [fn for fn in file_paths if fn.endswith('.py')]
260+
c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))]
261+
fixed = []
262+
fixed.extend(normalize_whitespace(python_files))
263+
fixed.extend(normalize_c_whitespace(c_files))
264+
if not fixed:
265+
print('No whitespace issues found')
266+
else:
267+
count = len(fixed)
268+
print(f'Please fix the {n_files_str(count)} with whitespace issues')
269+
print('(on Unix you can run `make patchcheck` to make the fixes)')
270+
sys.exit(1)
271+
272+
184273
def main():
185274
base_branch = get_base_branch()
186275
file_paths = changed_files(base_branch)
276+
python_files = [fn for fn in file_paths if fn.endswith('.py')]
277+
c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))]
187278
doc_files = [fn for fn in file_paths if fn.startswith('Doc') and
188279
fn.endswith(('.rst', '.inc'))]
189280
misc_files = {p for p in file_paths if p.startswith('Misc')}
281+
# PEP 8 whitespace rules enforcement.
282+
normalize_whitespace(python_files)
283+
# C rules enforcement.
284+
normalize_c_whitespace(c_files)
190285
# Docs updated.
191286
docs_modified(doc_files)
192287
# Misc/ACKS changed.
@@ -199,14 +294,19 @@ def main():
199294
regenerated_pyconfig_h_in(file_paths)
200295

201296
# Test suite run and passed.
202-
has_c_files = any(fn for fn in file_paths if fn.endswith(('.c', '.h')))
203-
has_python_files = any(fn for fn in file_paths if fn.endswith('.py'))
204-
print()
205-
if has_c_files:
206-
print("Did you run the test suite and check for refleaks?")
207-
elif has_python_files:
208-
print("Did you run the test suite?")
297+
if python_files or c_files:
298+
end = " and check for refleaks?" if c_files else "?"
299+
print()
300+
print("Did you run the test suite" + end)
209301

210302

211303
if __name__ == '__main__':
212-
main()
304+
import argparse
305+
parser = argparse.ArgumentParser(description=__doc__)
306+
parser.add_argument('--ci',
307+
help='Perform pass/fail checks')
308+
args = parser.parse_args()
309+
if args.ci:
310+
ci(args.ci)
311+
else:
312+
main()

0 commit comments

Comments
 (0)