Files
rio/tests/utils/ruff.py
2024-12-17 01:04:01 +01:00

74 lines
1.9 KiB
Python

import json
import subprocess
import sys
import tempfile
from pathlib import Path
__all__ = ["ruff_check", "ruff_format"]
def ruff_format(source_code: str) -> str:
# Write the source code to a temporary file
temp_file_path = Path(tempfile.gettempdir()) / "rio test suite tempfile.py"
temp_file_path.write_text(source_code, encoding="utf8")
# Run ruff to format the source code in the temporary file
ruff("format", temp_file_path)
# Read the formatted source code
return temp_file_path.read_text(encoding="utf8")
def ruff_check(source_code: str) -> list[str]:
"""
Checks the given source code using `ruff`. Returns any encountered problems.
"""
# Dump the source to a file, and implicitly define/import some stuff.
temp_file_path = Path(tempfile.gettempdir()) / "rio test suite tempfile.py"
temp_file_path.write_text(
f"""
import asyncio
import pathlib
import rio
Path = pathlib.Path
app = rio.App(build=rio.Spacer)
MyAppRoot = rio.Spacer
self = child1 = child2 = rio.Spacer()
{source_code}
""",
encoding="utf8",
)
# Run ruff to format the source code in the temporary file
proc = ruff(
"check",
temp_file_path,
# E402 = Import not at top of file
#
# F401 = Unused import
#
# F811 = Redefinition of a symbol. Happens if the source code already
# includes one of our injected imports.
"--ignore=E402,F401,F811",
"--output-format=json",
)
output = json.loads(proc.stdout)
assert isinstance(output, list), output
# Parse the output
return [entry["message"] for entry in output]
def ruff(*args: str | Path) -> subprocess.CompletedProcess:
return subprocess.run(
[sys.executable, "-m", "ruff", *map(str, args)],
# check=True,
capture_output=True,
text=True,
)