Plain is headed towards 1.0! Subscribe for development updates →

 1import subprocess
 2import sys
 3from pathlib import Path
 4
 5import click
 6import tomllib
 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")
44def fix(path, unsafe_fixes):
45    """Lint and format the given path."""
46    ruff_args = ["--config", str(DEFAULT_RUFF_CONFIG)]
47
48    for e in get_code_config().get("exclude", []):
49        ruff_args.extend(["--exclude", e])
50
51    if unsafe_fixes:
52        print_event("Ruff fix (with unsafe fixes)")
53        result = subprocess.run(
54            ["ruff", "check", path, "--fix", "--unsafe-fixes", *ruff_args]
55        )
56    else:
57        print_event("Ruff fix")
58        result = subprocess.run(["ruff", "check", path, "--fix", *ruff_args])
59
60    if result.returncode != 0:
61        sys.exit(result.returncode)
62
63    print_event("Ruff format")
64    result = subprocess.run(["ruff", "format", path, *ruff_args])
65
66    if result.returncode != 0:
67        sys.exit(result.returncode)
68
69
70def get_code_config():
71    pyproject = Path("pyproject.toml")
72    if not pyproject.exists():
73        return {}
74    with pyproject.open("rb") as f:
75        return tomllib.load(f).get("tool", {}).get("plain", {}).get("code", {})