From 9d87ca34ff78073e0a441f5dff13d77d6a927d14 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 14 Sep 2025 17:05:37 +0000 Subject: [PATCH 1/3] Initial plan From d30995c85022b463a362f2de26962a73d100dc07 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 14 Sep 2025 17:19:01 +0000 Subject: [PATCH 2/3] Add ImportError troubleshooting and conflict detection Co-authored-by: shenxianpeng <3353385+shenxianpeng@users.noreply.github.com> --- README.md | 44 +++++++++++++++++++++++++++++ cpp_linter_hooks/clang_format.py | 48 +++++++++++++++++++++++++++++++- cpp_linter_hooks/clang_tidy.py | 14 ++++++++-- 3 files changed, 102 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 193f308..7e68a46 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,50 @@ repos: args: [--style=file, --version=21, --verbose] # Add -v or --verbose for detailed output ``` +### ImportError: cannot import name 'clang_format' from 'clang_format' + +This error occurs when there are conflicting `clang-format` packages installed in your environment. The issue typically happens when: + +1. You previously installed PyPI packages like `clang-format` that provide conflicting scripts +2. Your environment has multiple versions of clang tools installed +3. There are leftover scripts from older versions of this hooks package + +**Solution 1: Remove conflicting packages** + +```bash +# Remove potentially conflicting packages +pip uninstall clang-format clang-tidy clang-tools + +# Reinstall cpp-linter-hooks cleanly +pip install --force-reinstall cpp-linter-hooks +``` + +**Solution 2: Check for conflicting scripts** + +```bash +# Check what clang-format script is being used +which clang-format + +# If it points to a conflicting script, remove it +rm $(which clang-format) # Only if it's the conflicting script +``` + +**Solution 3: Use specific entry points** + +Ensure your `.pre-commit-config.yaml` is using the latest configuration: + +```yaml +repos: + - repo: https://github.com/cpp-linter/cpp-linter-hooks + rev: v1.1.1 # Use the latest version + hooks: + - id: clang-format + args: [--style=file, --version=21] +``` + +> [!NOTE] +> This hooks package uses `clang-format-hook` and `clang-tidy-hook` as entry points, not the generic `clang-format` script. The error usually indicates that pre-commit is trying to use a conflicting `clang-format` script instead of the correct `clang-format-hook`. + ## FAQ ### What's the difference between [`cpp-linter-hooks`](https://github.com/cpp-linter/cpp-linter-hooks) and [`mirrors-clang-format`](https://github.com/pre-commit/mirrors-clang-format)? diff --git a/cpp_linter_hooks/clang_format.py b/cpp_linter_hooks/clang_format.py index ae732f6..b948fcb 100644 --- a/cpp_linter_hooks/clang_format.py +++ b/cpp_linter_hooks/clang_format.py @@ -1,11 +1,44 @@ import subprocess import sys +import os +import shutil from argparse import ArgumentParser from typing import Tuple from .util import ensure_installed, DEFAULT_CLANG_FORMAT_VERSION +def _check_for_conflicts() -> None: + """Check for potential conflicts with PyPI clang-format packages.""" + # Check if there's a conflicting clang-format script + clang_format_path = shutil.which("clang-format") + if clang_format_path: + try: + # Try to read the script to see if it contains the problematic import + with open(clang_format_path, 'r', encoding='utf-8') as f: + content = f.read() + if "from clang_format import clang_format" in content: + print( + "WARNING: Detected conflicting clang-format script at: " + clang_format_path, + file=sys.stderr + ) + print( + "This may cause ImportError. Consider removing conflicting packages:", + file=sys.stderr + ) + print( + " pip uninstall clang-format clang-tidy clang-tools", + file=sys.stderr + ) + print( + "For more help: https://github.com/cpp-linter/cpp-linter-hooks#importerror-cannot-import-name-clang_format-from-clang_format", + file=sys.stderr + ) + except (IOError, UnicodeDecodeError): + # If we can't read the file, ignore the check + pass + + parser = ArgumentParser() parser.add_argument("--version", default=DEFAULT_CLANG_FORMAT_VERSION) parser.add_argument( @@ -49,7 +82,16 @@ def run_clang_format(args=None) -> Tuple[int, str]: return retval, output except FileNotFoundError as e: - return 1, str(e) + error_msg = str(e) + # Provide helpful error message for missing clang-format + if "clang-format" in error_msg.lower(): + error_msg += "\nHint: The clang-format tool may not be installed or accessible." + error_msg += f"\nThis hook will try to install clang-format version {hook_args.version}." + return 1, error_msg + except Exception as e: + # Catch any other unexpected errors + error_msg = f"Unexpected error running clang-format: {str(e)}" + return 1, error_msg def _print_verbose_info(command: list, retval: int, output: str) -> None: @@ -61,6 +103,10 @@ def _print_verbose_info(command: list, retval: int, output: str) -> None: def main() -> int: + # Check for potential conflicts early + if os.environ.get("CLANG_FORMAT_HOOK_DEBUG"): + _check_for_conflicts() + retval, output = run_clang_format() # pragma: no cover # Print output for errors, but not for dry-run mode diff --git a/cpp_linter_hooks/clang_tidy.py b/cpp_linter_hooks/clang_tidy.py index 7f5dd5c..4e15732 100644 --- a/cpp_linter_hooks/clang_tidy.py +++ b/cpp_linter_hooks/clang_tidy.py @@ -24,9 +24,17 @@ def run_clang_tidy(args=None) -> Tuple[int, str]: if "warning:" in output or "error:" in output: retval = 1 return retval, output - except FileNotFoundError as stderr: - retval = 1 - return retval, str(stderr) + except FileNotFoundError as e: + error_msg = str(e) + # Provide helpful error message for missing clang-tidy + if "clang-tidy" in error_msg.lower(): + error_msg += "\nHint: The clang-tidy tool may not be installed or accessible." + error_msg += f"\nThis hook will try to install clang-tidy version {hook_args.version}." + return 1, error_msg + except Exception as e: + # Catch any other unexpected errors + error_msg = f"Unexpected error running clang-tidy: {str(e)}" + return 1, error_msg def main() -> int: From fcc5d65dcc41d16f0655ba6023e9ef9c8a4afa2a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 14 Sep 2025 17:21:38 +0000 Subject: [PATCH 3/3] Update README examples to use latest version v1.1.1 consistently Co-authored-by: shenxianpeng <3353385+shenxianpeng@users.noreply.github.com> --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7e68a46..a34bd1c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Add this configuration to your `.pre-commit-config.yaml` file: ```yaml repos: - repo: https://github.com/cpp-linter/cpp-linter-hooks - rev: v1.1.0 # Use the tag or commit you want + rev: v1.1.1 # Use the tag or commit you want hooks: - id: clang-format args: [--style=Google] # Other coding style: LLVM, GNU, Chromium, Microsoft, Mozilla, WebKit. @@ -46,7 +46,7 @@ To use custom configurations like `.clang-format` and `.clang-tidy`: ```yaml repos: - repo: https://github.com/cpp-linter/cpp-linter-hooks - rev: v1.1.0 + rev: v1.1.1 hooks: - id: clang-format args: [--style=file] # Loads style from .clang-format file @@ -61,7 +61,7 @@ To use specific versions of clang-format and clang-tidy (using Python wheel pack ```yaml repos: - repo: https://github.com/cpp-linter/cpp-linter-hooks - rev: v1.1.0 + rev: v1.1.1 hooks: - id: clang-format args: [--style=file, --version=21] # Specifies version @@ -151,7 +151,7 @@ Use -header-filter=.* to display errors from all non-system headers. Use -system ```yaml - repo: https://github.com/cpp-linter/cpp-linter-hooks - rev: v1.1.0 + rev: v1.1.1 hooks: - id: clang-format args: [--style=file, --version=21] @@ -177,7 +177,7 @@ This approach ensures that only modified files are checked, further speeding up ```yaml repos: - repo: https://github.com/cpp-linter/cpp-linter-hooks - rev: v1.1.0 + rev: v1.1.1 hooks: - id: clang-format args: [--style=file, --version=21, --verbose] # Add -v or --verbose for detailed output