Pre-commit hooks wrapper that auto-installs and runs clang-format and clang-tidy from Python wheels. Supports Python 3.9-3.14 across Windows, Linux, and macOS.
- Entry scripts:
clang-format-hookandclang-tidy-hook(defined inpyproject.toml) - Hook definitions:
.pre-commit-hooks.yamlconfigures both hooks withtypes_or: [c++, c] - Execution pattern: Parse args → resolve/install tool version → subprocess.run → return (exit_code, output)
clang_format.py: Wraps clang-format with-i(in-place), supports--verboseand--dry-runmodes- Returns
-1for dry-run to distinguish from actual failures
- Returns
clang_tidy.py: Wraps clang-tidy, forces exit code 1 if "warning:" or "error:" in outpututil.py: Dynamic version resolution via PyPI JSON API + pip-based tool installation_resolve_version_from_pypi(): Supports partial matches (e.g., "20" → "20.1.8"), resolves against PyPI in real time- No hardcoded version lists — versions are always up-to-date from PyPI
# Users can specify partial versions
--version=21 # Resolves to latest 21.x.x
--version=21.1 # Resolves to latest 21.1.x
--version=21.1.8 # Exact version# Test hooks locally without installing
pre-commit try-repo ./.. clang-format --verbose --all-files
pre-commit try-repo ./.. clang-tidy --verbose --all-files
# Run test suite
uv run pytest -vv # All tests
uv run coverage run -m pytest # With coverage
uv run pytest -m benchmark # Performance tests only- Update hook logic in
cpp_linter_hooks/{clang_format,clang_tidy}.py - Add tests in
tests/test_*.pywith@pytest.mark.benchmarkfor performance tracking - Test with sample files in
testing/directory (usegood.cas expected output) - Update README.md if user-facing behavior changes
- Uses
uvfor all dev operations (not pip directly) - Tool versions: Resolved dynamically from PyPI at hook runtime — no manual updates needed
- Version caching:
_get_pypi_versions()useslru_cacheto avoid repeated PyPI requests within a single run
All hook functions return Tuple[int, str]:
(0, "")→ Success(1, output)→ Failure (print output)(-1, output)→ Dry-run mode (clang-format only, convert to success in main)
- Use
tmp_pathfixture to avoid modifying repo files - Parametrize version tests:
@pytest.mark.parametrizewith versions 16-21 - Mark performance-sensitive tests with
@pytest.mark.benchmark - Compare formatted output against
testing/good.cfor correctness
# Standard pattern in both hooks
parser = ArgumentParser()
parser.add_argument("--version", default=DEFAULT_VERSION)
hook_args, other_args = parser.parse_known_args(args)
# ... install tool if needed ...
command = ["tool-name"] + other_args # Pass through unknown argspyproject.toml: Defines entry points and dependenciesutil.py: Core version resolution + tool installation logic.pre-commit-hooks.yaml: Hook metadata for pre-commit frameworktesting/run.sh: Integration test script used in CI
- Fetches available versions from
https://pypi.org/pypi/{package}/json - Filters out pre-release versions using regex pattern
(alpha|beta|rc|dev|a\d+|b\d+) - Installs via
subprocess.run([sys.executable, "-m", "pip", "install", f"{tool}=={version}"])
- Hooks run in parallel (
require_serial: false) for performance - File type filtering via
types_or: [c++, c] - Users configure via
.pre-commit-config.yamlwithargs:list
Add support for a new argument:
- Add to ArgumentParser in hook module
- Pass to subprocess command or handle in Python
- Add test case in
tests/test_*.py
No manual version updates needed: Tool versions are resolved dynamically from PyPI at runtime. When new versions are published to PyPI, hooks automatically discover them — no code changes required.
Debug hook failures:
- Add
--verboseto clang-format args for detailed output - Check
testing/run.shfor integration test patterns - Use
pre-commit run --verbosefor detailed pre-commit logs