From 7e5b85e8953c76b13baec5600ca9ed839c22ed30 Mon Sep 17 00:00:00 2001 From: rnetser Date: Wed, 13 May 2026 13:36:40 +0300 Subject: [PATCH] fix: fall back to ruff when prek fails outside git repo Backport of the file_writer fix from PR #2702 (main). prek requires a git repository to run. When generating files to temp directories (e.g. during tests), prek fails and generated code is left unformatted, causing test mismatches. Fall back to ruff with explicit --config pointing to the project's pyproject.toml. Assisted-by: Claude Signed-off-by: rnetser --- class_generator/formatters/file_writer.py | 47 ++++++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/class_generator/formatters/file_writer.py b/class_generator/formatters/file_writer.py index 9e662cf7de..2bd3c377b0 100644 --- a/class_generator/formatters/file_writer.py +++ b/class_generator/formatters/file_writer.py @@ -1,14 +1,19 @@ """File writing utilities for generated code.""" +from pathlib import Path + from pyhelper_utils.shell import run_command from simple_logger.logger import get_logger LOGGER = get_logger(name=__name__) +# Project root directory (contains pyproject.toml and .pre-commit-config.yaml) +_PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent + def write_and_format_rendered(filepath: str, output: str) -> None: """ - Write rendered content to file and format it with prek. + Write rendered content to file and format with prek, falling back to ruff. Args: filepath: Path to write the file to @@ -17,20 +22,50 @@ def write_and_format_rendered(filepath: str, output: str) -> None: with open(filepath, "w", encoding="utf-8") as fd: fd.write(output) - # Run prek on the file + pre_commit_config = str(_PROJECT_ROOT / ".pre-commit-config.yaml") + pyproject_toml = str(_PROJECT_ROOT / "pyproject.toml") + + # Try prek first (runs all pre-commit hooks including ruff) + prek_success = False try: rc, stdout, stderr = run_command( - command=["uvx", "prek", "run", "--files", filepath], + command=["uvx", "prek", "-c", pre_commit_config, "run", "--files", filepath], verify_stderr=False, check=False, log_errors=False, ) if not rc: if stderr: - LOGGER.warning(f"Prek hooks failed for {filepath}. This is non-fatal and generation will continue.") + LOGGER.warning(f"Prek hooks failed for {filepath}, falling back to ruff.") LOGGER.debug(f"prek stderr: {stderr}") + else: + prek_success = True + if stdout: LOGGER.info(f"{filepath} fixed by prek") - LOGGER.debug(f"rek stdout: {stdout}") + LOGGER.debug(f"prek stdout: {stdout}") except Exception as e: - LOGGER.error(f"Failed to run prek hooks for {filepath}: {e}. This is non-fatal and generation will continue.") + LOGGER.warning(f"Failed to run prek for {filepath}, falling back to ruff: {e}") + + if not prek_success: + _run_ruff_fallback(filepath=filepath, pyproject_toml=pyproject_toml) + + +def _run_ruff_fallback(filepath: str, pyproject_toml: str) -> None: + """Run ruff check --fix and ruff format as fallback when prek fails.""" + for ruff_cmd in ( + ["uvx", "ruff", "check", "--fix", "--config", pyproject_toml, filepath], + ["uvx", "ruff", "format", "--config", pyproject_toml, filepath], + ): + try: + _, stdout, _ = run_command( + command=ruff_cmd, + verify_stderr=False, + check=False, + log_errors=False, + ) + if stdout: + LOGGER.info(f"{filepath} fixed by ruff") + LOGGER.debug(f"ruff stdout: {stdout}") + except Exception as e: + LOGGER.error(f"Ruff fallback failed for {filepath}: {e}")