feat: add formatter module wrapping ruff and clang-format

This commit is contained in:
2026-06-14 06:54:28 -06:00
parent 56662a0520
commit b0a7ac9503
2 changed files with 78 additions and 0 deletions

45
formatter.py Normal file
View File

@@ -0,0 +1,45 @@
import subprocess
TIMEOUT_SECONDS = 5
CLANG_FORMAT_STYLE = "{BasedOnStyle: LLVM, IndentWidth: 4, BreakBeforeBraces: Allman}"
class FormatError(Exception):
"""代码格式化失败时抛出message 为可展示给用户的错误信息"""
def _run(cmd: list[str], code: str) -> str:
try:
result = subprocess.run(
cmd,
input=code,
capture_output=True,
text=True,
timeout=TIMEOUT_SECONDS,
)
except subprocess.TimeoutExpired:
raise FormatError("格式化超时")
if result.returncode != 0:
raise FormatError(result.stderr.strip() or "格式化失败")
return result.stdout
def format_code(code: str, language: str) -> str:
if language in ("python", "turtle"):
return _run(["ruff", "format", "-", "--stdin-filename", "main.py"], code)
if language in ("c", "cpp"):
ext = "c" if language == "c" else "cpp"
return _run(
[
"clang-format",
f"-style={CLANG_FORMAT_STYLE}",
f"-assume-filename=main.{ext}",
],
code,
)
raise FormatError(f"不支持的语言: {language}")

33
test_formatter.py Normal file
View File

@@ -0,0 +1,33 @@
import pytest
from formatter import FormatError, format_code
def test_format_python_normalizes_spacing():
result = format_code("x=1\n", "python")
assert result == "x = 1\n"
def test_format_turtle_uses_python_formatter():
result = format_code("t=1\n", "turtle")
assert result == "t = 1\n"
def test_format_python_syntax_error_raises():
with pytest.raises(FormatError):
format_code("def foo(:\n", "python")
def test_format_c_uses_allman_braces():
result = format_code("int main(){int x=1;return x;}", "c")
assert result.rstrip("\n") == "int main()\n{\n int x = 1;\n return x;\n}"
def test_format_cpp_uses_allman_braces():
result = format_code("class Foo{};", "cpp")
assert result.rstrip("\n") == "class Foo\n{\n};"
def test_format_unsupported_language_raises():
with pytest.raises(FormatError):
format_code("print(1)", "java")