Coverage for formkit_ninja / parser / formatter.py: 17.65%
30 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-03-06 04:12 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-03-06 04:12 +0000
1"""
2Code formatter using ruff.
4This module provides a CodeFormatter class that uses ruff format
5to format Python code strings.
6"""
8import subprocess
9from typing import Optional
12class FormattingError(Exception):
13 """Exception raised when code formatting fails."""
15 def __init__(self, message: str, original_error: Optional[Exception] = None) -> None:
16 """Initialize FormattingError with a message and optional original error.
18 Args:
19 message: Error message describing what went wrong
20 original_error: The original exception that caused the formatting error
21 """
22 super().__init__(message)
23 self.message = message
24 self.original_error = original_error
27class CodeFormatter:
28 """Formatter for Python code using ruff format."""
30 def format(self, code: str) -> str:
31 """Format Python code using ruff format.
33 Args:
34 code: The Python code string to format
36 Returns:
37 The formatted Python code string
39 Raises:
40 FormattingError: If formatting fails (invalid syntax, ruff not found, etc.)
41 """
42 if not code.strip():
43 # Handle empty or whitespace-only strings
44 return code
46 try:
47 # Use ruff format via subprocess
48 # --stdin-filename ensures ruff treats input as Python code
49 result = subprocess.run(
50 ["ruff", "format", "--stdin-filename", "code.py"],
51 input=code.encode("utf-8"),
52 capture_output=True,
53 check=True,
54 text=False, # We handle encoding manually
55 )
57 # Decode the formatted output
58 formatted = result.stdout.decode("utf-8")
60 return formatted
62 except FileNotFoundError as e:
63 raise FormattingError(
64 "ruff command not found. Please ensure ruff is installed and in your PATH.",
65 original_error=e,
66 ) from e
68 except subprocess.CalledProcessError as e:
69 # Ruff returned non-zero exit code (usually syntax errors)
70 error_message = "Code formatting failed"
71 if e.stderr:
72 try:
73 stderr_text = e.stderr.decode("utf-8")
74 error_message = f"Code formatting failed: {stderr_text}"
75 except (UnicodeDecodeError, AttributeError):
76 error_message = f"Code formatting failed (exit code {e.returncode})"
78 raise FormattingError(error_message, original_error=e) from e
80 except subprocess.SubprocessError as e:
81 raise FormattingError(
82 f"Subprocess error during formatting: {str(e)}",
83 original_error=e,
84 ) from e
86 except Exception as e:
87 raise FormattingError(
88 f"Unexpected error during formatting: {str(e)}",
89 original_error=e,
90 ) from e