Skip to content

Commit

Permalink
feat: support multiple "pyproject.toml" files (#46)
Browse files Browse the repository at this point in the history
* feat: implement pyproject_tomls

* ci: pass type check
  • Loading branch information
KyleKing committed Nov 23, 2022
1 parent 6b08288 commit c690ab2
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 35 deletions.
45 changes: 23 additions & 22 deletions src/pyproject_fmt/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,31 @@ def color_diff(diff: Iterable[str]) -> Iterable[str]:

def run(args: Sequence[str] | None = None) -> int:
opts = cli_args(sys.argv[1:] if args is None else args)
config = opts.as_config
formatted = format_pyproject(config)
toml = opts.pyproject_toml
before = config.toml
changed = before != formatted
if opts.stdout: # stdout just prints new format to stdout
print(formatted, end="")
else:
toml.write_text(formatted, encoding="utf-8")
try:
name = str(toml.relative_to(Path.cwd()))
except ValueError:
name = str(toml)
diff: Iterable[str] = []
if changed:
diff = difflib.unified_diff(before.splitlines(), formatted.splitlines(), fromfile=name, tofile=name)

if diff:
diff = color_diff(diff)
print("\n".join(diff)) # print diff on change
any_modified = False
for config in opts.as_configs:
formatted = format_pyproject(config)
before = config.toml
changed = before != formatted
any_modified = any_modified or changed
if opts.stdout: # stdout just prints new format to stdout
print(formatted, end="")
else:
print(f"no change for {name}")
config.pyproject_toml.write_text(formatted, encoding="utf-8")
try:
name = str(config.pyproject_toml.relative_to(Path.cwd()))
except ValueError:
name = str(config.pyproject_toml)
diff: Iterable[str] = []
if changed:
diff = difflib.unified_diff(before.splitlines(), formatted.splitlines(), fromfile=name, tofile=name)

if diff:
diff = color_diff(diff)
print("\n".join(diff)) # print diff on change
else:
print(f"no change for {name}")
# exit with non success on change
return 1 if changed else 0
return 1 if any_modified else 0


if __name__ == "__main__":
Expand Down
20 changes: 13 additions & 7 deletions src/pyproject_fmt/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,20 @@
class PyProjectFmtNamespace(Namespace):
"""Options for pyproject-fmt tool"""

pyproject_toml: Path
pyproject_tomls: list[Path]
stdout: bool
indent: int

@property
def as_config(self) -> Config:
return Config(
toml=self.pyproject_toml.read_text(encoding="utf-8"),
indent=self.indent,
)
def as_configs(self) -> list[Config]:
return [
Config(
pyproject_toml=pyproject_toml,
toml=pyproject_toml.read_text(encoding="utf-8"),
indent=self.indent,
)
for pyproject_toml in self.pyproject_tomls
]


def pyproject_toml_path_creator(argument: str) -> Path:
Expand All @@ -51,7 +55,9 @@ def _build_cli() -> ArgumentParser:
msg = "print the formatted text to the stdout (instead of update in-place)"
parser.add_argument("-s", "--stdout", action="store_true", help=msg)
parser.add_argument("--indent", type=int, default=DEFAULT_INDENT, help="number of spaces to indent")
parser.add_argument("pyproject_toml", type=pyproject_toml_path_creator, help="pyproject.toml file to format")
parser.add_argument(
"pyproject_tomls", nargs="+", type=pyproject_toml_path_creator, help="pyproject.toml file(s) to format"
)
return parser


Expand Down
2 changes: 2 additions & 0 deletions src/pyproject_fmt/formatter/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import sys
from dataclasses import dataclass
from pathlib import Path

if sys.version_info >= (3, 8): # pragma: no cover (py38+)
from typing import Final
Expand All @@ -16,6 +17,7 @@
class Config:
"""Configuration flags for the formatting."""

pyproject_toml: Path
toml: str #: the text to format
indent: int = DEFAULT_INDENT #: indentation to apply

Expand Down
3 changes: 2 additions & 1 deletion tests/formatter/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

from pathlib import Path
from textwrap import dedent
from typing import Callable

Expand All @@ -16,7 +17,7 @@
def fmt(mocker: MockerFixture) -> Fmt:
def _func(formatter: Callable[[TOMLDocument, Config], None], start: str, expected: str) -> None:
mocker.patch("pyproject_fmt.formatter._perform", formatter)
opts = Config(toml=dedent(start))
opts = Config(pyproject_toml=Path(), toml=dedent(start))
result = format_pyproject(opts)

expected = dedent(expected)
Expand Down
20 changes: 15 additions & 5 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@ def test_cli_pyproject_toml_ok(tmp_path: Path) -> None:
path = tmp_path / "tox.ini"
path.write_text("")
result = cli_args([str(path)])
assert result.pyproject_toml == path
assert result.pyproject_tomls == [path]


def test_cli_pyproject_tomls_ok(tmp_path: Path) -> None:
paths = []
for filename in ("tox.ini", "tox2.ini", "tox3.ini"):
path = tmp_path / filename
path.write_text("")
paths.append(path)
result = cli_args([*map(str, paths)])
assert result.pyproject_tomls == paths


def test_cli_pyproject_toml_not_exists(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
Expand All @@ -22,7 +32,7 @@ def test_cli_pyproject_toml_not_exists(tmp_path: Path, capsys: pytest.CaptureFix
assert context.value.code != 0
out, err = capsys.readouterr()
assert not out
assert "argument pyproject_toml: path does not exist" in err
assert "argument pyproject_tomls: path does not exist" in err


def test_cli_pyproject_toml_not_file(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
Expand All @@ -31,7 +41,7 @@ def test_cli_pyproject_toml_not_file(tmp_path: Path, capsys: pytest.CaptureFixtu
assert context.value.code != 0
out, err = capsys.readouterr()
assert not out
assert "argument pyproject_toml: path is not a file" in err
assert "argument pyproject_tomls: path is not a file" in err


@pytest.mark.parametrize(("flag", "error"), [(S_IREAD, "write"), (S_IWRITE, "read")])
Expand All @@ -50,12 +60,12 @@ def test_cli_pyproject_toml_permission_fail(
assert context.value.code != 0
out, err = capsys.readouterr()
assert not out
assert f"argument pyproject_toml: cannot {error} path" in err
assert f"argument pyproject_tomls: cannot {error} path" in err


def test_pyproject_toml_resolved(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.chdir(tmp_path)
path = tmp_path / "tox.ini"
path.write_text("")
result = cli_args(["tox.ini"])
assert result.pyproject_toml == path
assert result.pyproject_tomls == [path]
1 change: 1 addition & 0 deletions whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ skipif
tofile
toml
tomlkit
tomls
typehints

0 comments on commit c690ab2

Please sign in to comment.