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