Plain is headed towards 1.0! Subscribe for development updates →

 1import subprocess
 2import sys
 3import tomllib
 4from pathlib import Path
 5
 6import click
 7
 8from plain.cli import register_cli
 9from plain.cli.print import print_event
10
11DEFAULT_RUFF_CONFIG = Path(__file__).parent / "ruff_defaults.toml"
12
13
14@register_cli("code")
15@click.group()
16def cli():
17    """Code formatting and linting"""
18    pass
19
20
21@cli.command()
22@click.argument("path", default=".")
23def check(path):
24    """Check the given path for formatting or linting issues."""
25    ruff_args = ["--config", str(DEFAULT_RUFF_CONFIG)]
26
27    for e in get_code_config().get("exclude", []):
28        ruff_args.extend(["--exclude", e])
29
30    print_event("Ruff check")
31    result = subprocess.run(["ruff", "check", path, *ruff_args])
32
33    if result.returncode != 0:
34        sys.exit(result.returncode)
35
36    print_event("Ruff format check")
37    result = subprocess.run(["ruff", "format", path, "--check", *ruff_args])
38
39    if result.returncode != 0:
40        sys.exit(result.returncode)
41
42
43@register_cli("fix")
44@cli.command()
45@click.argument("path", default=".")
46@click.option("--unsafe-fixes", is_flag=True, help="Apply ruff unsafe fixes")
47@click.option("--add-noqa", is_flag=True, help="Add noqa comments to suppress errors")
48def fix(path, unsafe_fixes, add_noqa):
49    """Lint and format the given path."""
50    ruff_args = ["--config", str(DEFAULT_RUFF_CONFIG)]
51
52    for e in get_code_config().get("exclude", []):
53        ruff_args.extend(["--exclude", e])
54
55    if unsafe_fixes and add_noqa:
56        print("Cannot use both --unsafe-fixes and --add-noqa")
57        sys.exit(1)
58
59    if unsafe_fixes:
60        print_event("Ruff fix (with unsafe fixes)")
61        result = subprocess.run(
62            ["ruff", "check", path, "--fix", "--unsafe-fixes", *ruff_args]
63        )
64    elif add_noqa:
65        print_event("Ruff fix (add noqa)")
66        result = subprocess.run(["ruff", "check", path, "--add-noqa", *ruff_args])
67    else:
68        print_event("Ruff fix")
69        result = subprocess.run(["ruff", "check", path, "--fix", *ruff_args])
70
71    if result.returncode != 0:
72        sys.exit(result.returncode)
73
74    print_event("Ruff format")
75    result = subprocess.run(["ruff", "format", path, *ruff_args])
76
77    if result.returncode != 0:
78        sys.exit(result.returncode)
79
80
81def get_code_config():
82    pyproject = Path("pyproject.toml")
83    if not pyproject.exists():
84        return {}
85    with pyproject.open("rb") as f:
86        return tomllib.load(f).get("tool", {}).get("plain", {}).get("code", {})