]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] gh-109408: Revert pre-commit whitespace checks pending portable solution ...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 11 Oct 2023 16:37:41 +0000 (18:37 +0200)
committerGitHub <noreply@github.com>
Wed, 11 Oct 2023 16:37:41 +0000 (16:37 +0000)
gh-109408: Revert pre-commit whitespace checks pending portable solution (GH-110726)
(cherry picked from commit de956b263b98bb9928ce4377c42ca8271c4f2682)

Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>
.pre-commit-config.yaml
Tools/patchcheck/patchcheck.py

index 9a27d30fd4163e64a5f893b88a9456dc96212f1f..5b362a7c9d4c8aa84352e0628f1f4d2649eca2b5 100644 (file)
@@ -23,30 +23,6 @@ repos:
       - id: trailing-whitespace
         types_or: [c, inc, python, rst]
 
-  - repo: local
-    hooks:
-      - id: python-file-whitespace
-        name: "Check Python file whitespace"
-        entry: 'python Tools/patchcheck/reindent.py --nobackup --newline LF'
-        language: 'system'
-        types: [python]
-        exclude: '^(Lib/test/tokenizedata/|Tools/c-analyzer/cpython/_parser).*$'
-
-  - repo: local
-    hooks:
-      - id: c-file-whitespace
-        name: "Check C file whitespace"
-        entry: "python Tools/patchcheck/untabify.py"
-        language: "system"
-        types_or: ['c', 'c++']
-        # Don't check the style of vendored libraries
-        exclude: |
-          (?x)^(
-            Modules/_decimal/.*
-            | Modules/libmpdec/.*
-            | Modules/expat/.*
-          )$
-
   - repo: https://github.com/sphinx-contrib/sphinx-lint
     rev: v0.6.8
     hooks:
index 66328c8becc1f6dc9dc48b1e2e7d950a51f8f671..af1f0584bb54035e8221ce805aa63a1f096bcbdc 100755 (executable)
@@ -1,15 +1,30 @@
 #!/usr/bin/env python3
 """Check proposed changes for common issues."""
+import re
 import sys
+import shutil
 import os.path
 import subprocess
 import sysconfig
 
+import reindent
+import untabify
+
+
 def get_python_source_dir():
     src_dir = sysconfig.get_config_var('abs_srcdir')
     if not src_dir:
         src_dir = sysconfig.get_config_var('srcdir')
     return os.path.abspath(src_dir)
+
+
+# Excluded directories which are copies of external libraries:
+# don't check their coding style
+EXCLUDE_DIRS = [
+    os.path.join('Modules', '_decimal', 'libmpdec'),
+    os.path.join('Modules', 'expat'),
+    os.path.join('Modules', 'zlib'),
+    ]
 SRCDIR = get_python_source_dir()
 
 
@@ -140,8 +155,62 @@ def changed_files(base_branch=None):
     else:
         sys.exit('need a git checkout to get modified files')
 
-    # Normalize the path to be able to match using str.startswith()
-    return list(map(os.path.normpath, filenames))
+    filenames2 = []
+    for filename in filenames:
+        # Normalize the path to be able to match using .startswith()
+        filename = os.path.normpath(filename)
+        if any(filename.startswith(path) for path in EXCLUDE_DIRS):
+            # Exclude the file
+            continue
+        filenames2.append(filename)
+
+    return filenames2
+
+
+def report_modified_files(file_paths):
+    count = len(file_paths)
+    if count == 0:
+        return n_files_str(count)
+    else:
+        lines = [f"{n_files_str(count)}:"]
+        for path in file_paths:
+            lines.append(f"  {path}")
+        return "\n".join(lines)
+
+
+#: Python files that have tabs by design:
+_PYTHON_FILES_WITH_TABS = frozenset({
+    'Tools/c-analyzer/cpython/_parser.py',
+})
+
+
+@status("Fixing Python file whitespace", info=report_modified_files)
+def normalize_whitespace(file_paths):
+    """Make sure that the whitespace for .py files have been normalized."""
+    reindent.makebackup = False  # No need to create backups.
+    fixed = [
+        path for path in file_paths
+        if (
+            path.endswith('.py')
+            and path not in _PYTHON_FILES_WITH_TABS
+            and reindent.check(os.path.join(SRCDIR, path))
+        )
+    ]
+    return fixed
+
+
+@status("Fixing C file whitespace", info=report_modified_files)
+def normalize_c_whitespace(file_paths):
+    """Report if any C files """
+    fixed = []
+    for path in file_paths:
+        abspath = os.path.join(SRCDIR, path)
+        with open(abspath, 'r') as f:
+            if '\t' not in f.read():
+                continue
+        untabify.process(abspath, 8, verbose=False)
+        fixed.append(path)
+    return fixed
 
 
 @status("Docs modified", modal=True)
@@ -181,12 +250,38 @@ def regenerated_pyconfig_h_in(file_paths):
         return "not needed"
 
 
+def ci(pull_request):
+    if pull_request == 'false':
+        print('Not a pull request; skipping')
+        return
+    base_branch = get_base_branch()
+    file_paths = changed_files(base_branch)
+    python_files = [fn for fn in file_paths if fn.endswith('.py')]
+    c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))]
+    fixed = []
+    fixed.extend(normalize_whitespace(python_files))
+    fixed.extend(normalize_c_whitespace(c_files))
+    if not fixed:
+        print('No whitespace issues found')
+    else:
+        count = len(fixed)
+        print(f'Please fix the {n_files_str(count)} with whitespace issues')
+        print('(on Unix you can run `make patchcheck` to make the fixes)')
+        sys.exit(1)
+
+
 def main():
     base_branch = get_base_branch()
     file_paths = changed_files(base_branch)
+    python_files = [fn for fn in file_paths if fn.endswith('.py')]
+    c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))]
     doc_files = [fn for fn in file_paths if fn.startswith('Doc') and
                  fn.endswith(('.rst', '.inc'))]
     misc_files = {p for p in file_paths if p.startswith('Misc')}
+    # PEP 8 whitespace rules enforcement.
+    normalize_whitespace(python_files)
+    # C rules enforcement.
+    normalize_c_whitespace(c_files)
     # Docs updated.
     docs_modified(doc_files)
     # Misc/ACKS changed.
@@ -199,14 +294,19 @@ def main():
     regenerated_pyconfig_h_in(file_paths)
 
     # Test suite run and passed.
-    has_c_files = any(fn for fn in file_paths if fn.endswith(('.c', '.h')))
-    has_python_files = any(fn for fn in file_paths if fn.endswith('.py'))
-    print()
-    if has_c_files:
-        print("Did you run the test suite and check for refleaks?")
-    elif has_python_files:
-        print("Did you run the test suite?")
+    if python_files or c_files:
+        end = " and check for refleaks?" if c_files else "?"
+        print()
+        print("Did you run the test suite" + end)
 
 
 if __name__ == '__main__':
-    main()
+    import argparse
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument('--ci',
+                        help='Perform pass/fail checks')
+    args = parser.parse_args()
+    if args.ci:
+        ci(args.ci)
+    else:
+        main()