From 47140e79485393bf8c9b073082a7b5d71adfb7e4 Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Wed, 16 Jul 2025 17:21:06 +0300 Subject: [PATCH 1/8] fix: Update pyproject.toml to move deps to optional --- pyproject.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 798646d..98f8fba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,8 +32,6 @@ classifiers = [ "Topic :: Software Development :: Build Tools", ] dependencies = [ - "clang-format==20.1.7", - "clang-tidy==20.1.0", "tomli>=1.1.0; python_version < '3.11'", ] dynamic = ["version"] @@ -47,6 +45,11 @@ source = "https://github.com/cpp-linter/cpp-linter-hooks" tracker = "https://github.com/cpp-linter/cpp-linter-hooks/issues" [project.optional-dependencies] +tools = [ + "clang-format==20.1.7", + "clang-tidy==20.1.0", +] + dev = [ "coverage", "pre-commit", From 789b90bf1b49e2478ea328207915221d699ed4b4 Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Wed, 16 Jul 2025 20:53:35 +0300 Subject: [PATCH 2/8] fix: update get deps function to work --- cpp_linter_hooks/util.py | 7 +++++-- pyproject.toml | 1 + tests/test_util.py | 40 ++++++++++++++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/cpp_linter_hooks/util.py b/cpp_linter_hooks/util.py index 3f97c13..59c8abc 100644 --- a/cpp_linter_hooks/util.py +++ b/cpp_linter_hooks/util.py @@ -20,10 +20,13 @@ def get_version_from_dependency(tool: str) -> Optional[str]: return None with open(pyproject_path, "rb") as f: data = tomllib.load(f) - dependencies = data.get("project", {}).get("dependencies", []) - for dep in dependencies: + # First try project.optional-dependencies.tools + optional_deps = data.get("project", {}).get("optional-dependencies", {}) + tools_deps = optional_deps.get("tools", []) + for dep in tools_deps: if dep.startswith(f"{tool}=="): return dep.split("==")[1] + return None diff --git a/pyproject.toml b/pyproject.toml index 98f8fba..07e96a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,6 +45,7 @@ source = "https://github.com/cpp-linter/cpp-linter-hooks" tracker = "https://github.com/cpp-linter/cpp-linter-hooks/issues" [project.optional-dependencies] +# only clang tools can added to this section to make hooks work tools = [ "clang-format==20.1.7", "clang-tidy==20.1.0", diff --git a/tests/test_util.py b/tests/test_util.py index ecf5258..aab7de5 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -102,11 +102,13 @@ def test_get_version_from_dependency_success(): """Test get_version_from_dependency with valid pyproject.toml.""" mock_toml_content = { "project": { - "dependencies": [ - "clang-format==20.1.7", - "clang-tidy==20.1.0", - "other-package==1.0.0", - ] + "optional-dependencies": { + "tools": [ + "clang-format==20.1.7", + "clang-tidy==20.1.0", + "other-package==1.0.0", + ] + } } } @@ -132,7 +134,9 @@ def test_get_version_from_dependency_missing_file(): @pytest.mark.benchmark def test_get_version_from_dependency_missing_dependency(): """Test get_version_from_dependency with missing dependency.""" - mock_toml_content = {"project": {"dependencies": ["other-package==1.0.0"]}} + mock_toml_content = { + "project": {"optional-dependencies": {"tools": ["other-package==1.0.0"]}} + } with ( patch("pathlib.Path.exists", return_value=True), @@ -155,6 +159,30 @@ def test_get_version_from_dependency_malformed_toml(): assert result is None +@pytest.mark.benchmark +def test_get_version_from_dependency_fallback_to_dependencies(): + """Test get_version_from_dependency falls back to project.dependencies.""" + mock_toml_content = { + "project": { + "dependencies": [ + "clang-format==20.1.7", + "clang-tidy==20.1.0", + "other-package==1.0.0", + ] + } + } + + with ( + patch("pathlib.Path.exists", return_value=True), + patch("cpp_linter_hooks.util.tomllib.load", return_value=mock_toml_content), + ): + result = get_version_from_dependency("clang-format") + assert result == "20.1.7" + + result = get_version_from_dependency("clang-tidy") + assert result == "20.1.0" + + # Tests for _resolve_version @pytest.mark.benchmark @pytest.mark.parametrize( From 7e6bf7a1b1a7cdb337a4572b694f41d54713415d Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Wed, 16 Jul 2025 20:55:10 +0300 Subject: [PATCH 3/8] fix: remove fall back function --- tests/test_util.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/tests/test_util.py b/tests/test_util.py index aab7de5..9ffb921 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -159,30 +159,6 @@ def test_get_version_from_dependency_malformed_toml(): assert result is None -@pytest.mark.benchmark -def test_get_version_from_dependency_fallback_to_dependencies(): - """Test get_version_from_dependency falls back to project.dependencies.""" - mock_toml_content = { - "project": { - "dependencies": [ - "clang-format==20.1.7", - "clang-tidy==20.1.0", - "other-package==1.0.0", - ] - } - } - - with ( - patch("pathlib.Path.exists", return_value=True), - patch("cpp_linter_hooks.util.tomllib.load", return_value=mock_toml_content), - ): - result = get_version_from_dependency("clang-format") - assert result == "20.1.7" - - result = get_version_from_dependency("clang-tidy") - assert result == "20.1.0" - - # Tests for _resolve_version @pytest.mark.benchmark @pytest.mark.parametrize( From fb84f577c9ac4cf0259b43b1f971abfbcc3627d9 Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Wed, 16 Jul 2025 21:03:02 +0300 Subject: [PATCH 4/8] fix: get deps func --- cpp_linter_hooks/util.py | 13 +++++++++++-- tests/test_util.py | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/cpp_linter_hooks/util.py b/cpp_linter_hooks/util.py index 59c8abc..84960b3 100644 --- a/cpp_linter_hooks/util.py +++ b/cpp_linter_hooks/util.py @@ -27,11 +27,16 @@ def get_version_from_dependency(tool: str) -> Optional[str]: if dep.startswith(f"{tool}=="): return dep.split("==")[1] + # Fallback to project.dependencies for backward compatibility + dependencies = data.get("project", {}).get("dependencies", []) + for dep in dependencies: + if dep.startswith(f"{tool}=="): + return dep.split("==")[1] return None -DEFAULT_CLANG_FORMAT_VERSION = get_version_from_dependency("clang-format") -DEFAULT_CLANG_TIDY_VERSION = get_version_from_dependency("clang-tidy") +DEFAULT_CLANG_FORMAT_VERSION = get_version_from_dependency("clang-format") or "20.1.7" +DEFAULT_CLANG_TIDY_VERSION = get_version_from_dependency("clang-tidy") or "20.1.0" CLANG_FORMAT_VERSIONS = [ @@ -179,6 +184,10 @@ def _resolve_install(tool: str, version: Optional[str]) -> Optional[Path]: else DEFAULT_CLANG_TIDY_VERSION ) + # Additional safety check in case DEFAULT versions are None + if user_version is None: + user_version = "20.1.7" if tool == "clang-format" else "20.1.0" + path = shutil.which(tool) if path: runtime_version = _get_runtime_version(tool) diff --git a/tests/test_util.py b/tests/test_util.py index 9ffb921..e06a1fa 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -427,3 +427,22 @@ def test_version_lists_not_empty(): assert len(CLANG_TIDY_VERSIONS) > 0 assert all(isinstance(v, str) for v in CLANG_FORMAT_VERSIONS) assert all(isinstance(v, str) for v in CLANG_TIDY_VERSIONS) + + +@pytest.mark.benchmark +def test_resolve_install_with_none_default_version(): + """Test _resolve_install when DEFAULT versions are None.""" + with ( + patch("shutil.which", return_value=None), + patch("cpp_linter_hooks.util.DEFAULT_CLANG_FORMAT_VERSION", None), + patch("cpp_linter_hooks.util.DEFAULT_CLANG_TIDY_VERSION", None), + patch( + "cpp_linter_hooks.util._install_tool", + return_value=Path("/usr/bin/clang-format"), + ) as mock_install, + ): + result = _resolve_install("clang-format", None) + assert result == Path("/usr/bin/clang-format") + + # Should fallback to hardcoded version when DEFAULT is None + mock_install.assert_called_once_with("clang-format", "20.1.7") From 3bbd3104e7db241f9e7ea96794df22b482a2fd5e Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Wed, 16 Jul 2025 21:26:51 +0300 Subject: [PATCH 5/8] fix: add setuptools for testing --- .github/workflows/test.yml | 1 + pyproject.toml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index abb783d..d520653 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,6 +27,7 @@ jobs: run: | python -m pip install --upgrade pip pip install .[dev] + pip install setuptools # Ensure setuptools is available for pkg_resources - name: Run tests and collect coverage run: | diff --git a/pyproject.toml b/pyproject.toml index 07e96a6..7808ed9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,7 @@ classifiers = [ ] dependencies = [ "tomli>=1.1.0; python_version < '3.11'", + "setuptools>=45.0.0", ] dynamic = ["version"] @@ -49,6 +50,7 @@ tracker = "https://github.com/cpp-linter/cpp-linter-hooks/issues" tools = [ "clang-format==20.1.7", "clang-tidy==20.1.0", + "setuptools>=45.0.0", # Required for pkg_resources in clang-tidy ] dev = [ From 7d82a568dce79959391931526c02637f1300f187 Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Wed, 16 Jul 2025 21:30:13 +0300 Subject: [PATCH 6/8] fix: update pyproject.toml --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7808ed9..816601f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ classifiers = [ ] dependencies = [ "tomli>=1.1.0; python_version < '3.11'", - "setuptools>=45.0.0", + "setuptools>=45.0.0", # Required for pkg_resources in clang-tidy ] dynamic = ["version"] @@ -50,7 +50,6 @@ tracker = "https://github.com/cpp-linter/cpp-linter-hooks/issues" tools = [ "clang-format==20.1.7", "clang-tidy==20.1.0", - "setuptools>=45.0.0", # Required for pkg_resources in clang-tidy ] dev = [ From e748d105ff52b5436debb3e9b4e69742e247c212 Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Wed, 16 Jul 2025 21:36:13 +0300 Subject: [PATCH 7/8] fix: code refactor --- .github/workflows/test.yml | 1 - cpp_linter_hooks/util.py | 10 +++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d520653..abb783d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,6 @@ jobs: run: | python -m pip install --upgrade pip pip install .[dev] - pip install setuptools # Ensure setuptools is available for pkg_resources - name: Run tests and collect coverage run: | diff --git a/cpp_linter_hooks/util.py b/cpp_linter_hooks/util.py index 84960b3..13a7efc 100644 --- a/cpp_linter_hooks/util.py +++ b/cpp_linter_hooks/util.py @@ -35,8 +35,8 @@ def get_version_from_dependency(tool: str) -> Optional[str]: return None -DEFAULT_CLANG_FORMAT_VERSION = get_version_from_dependency("clang-format") or "20.1.7" -DEFAULT_CLANG_TIDY_VERSION = get_version_from_dependency("clang-tidy") or "20.1.0" +DEFAULT_CLANG_FORMAT_VERSION = get_version_from_dependency("clang-format") +DEFAULT_CLANG_TIDY_VERSION = get_version_from_dependency("clang-tidy") CLANG_FORMAT_VERSIONS = [ @@ -186,7 +186,11 @@ def _resolve_install(tool: str, version: Optional[str]) -> Optional[Path]: # Additional safety check in case DEFAULT versions are None if user_version is None: - user_version = "20.1.7" if tool == "clang-format" else "20.1.0" + user_version = ( + DEFAULT_CLANG_FORMAT_VERSION + if tool == "clang-format" + else DEFAULT_CLANG_TIDY_VERSION + ) path = shutil.which(tool) if path: From b8eb49e48f5539cd0bbe64c8d18c51c6f2259c01 Mon Sep 17 00:00:00 2001 From: shenxianpeng Date: Wed, 16 Jul 2025 21:40:14 +0300 Subject: [PATCH 8/8] fix: update tests --- tests/test_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_util.py b/tests/test_util.py index e06a1fa..48cc448 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -445,4 +445,4 @@ def test_resolve_install_with_none_default_version(): assert result == Path("/usr/bin/clang-format") # Should fallback to hardcoded version when DEFAULT is None - mock_install.assert_called_once_with("clang-format", "20.1.7") + mock_install.assert_called_once_with("clang-format", None)