-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature/12 implement usethis tool deptry (#13)
* Add deptry function which installs deptry via uv as a dev dependency. * Add progress message for usethis tool deptry. * Add tests for running deptry after calling `usethis tool deptry`. * Remove hello function. * Configure the package as a CLI app using typer. * Reword message for usethis tool deptry * Reword message for usethis tool deptry * Use rich for console output * Set PYTHONIOENCODING explicitly in CI config.
- Loading branch information
1 parent
957fb23
commit c9b2fa6
Showing
8 changed files
with
317 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
def hello() -> str: | ||
return "Hello from usethis!" | ||
from rich.console import Console | ||
|
||
console = Console() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import typer | ||
|
||
import usethis.tool | ||
|
||
app = typer.Typer( | ||
help=( | ||
"🤖 Automate Python package and project setup tasks that are otherwise " | ||
"performed manually." | ||
) | ||
) | ||
app.add_typer(usethis.tool.app, name="tool") | ||
app(prog_name="usethis") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import subprocess | ||
|
||
import typer | ||
|
||
from usethis import console | ||
|
||
app = typer.Typer(help="Add and configure development tools, e.g. linters") | ||
|
||
|
||
@app.command( | ||
help="Use the deptry linter: avoid missing or superfluous dependency declarations." | ||
) | ||
def deptry() -> None: | ||
console.print("✔ Ensuring deptry is a development dependency", style="green") | ||
subprocess.run(["uv", "add", "--dev", "--quiet", "deptry"], check=True) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import os | ||
import subprocess | ||
from contextlib import contextmanager | ||
from pathlib import Path | ||
from typing import Generator | ||
|
||
import pytest | ||
import tomlkit | ||
from pydantic import TypeAdapter | ||
|
||
from usethis.tool import deptry | ||
|
||
|
||
@contextmanager | ||
def change_cwd(new_dir: Path) -> Generator[None, None, None]: | ||
"""Change the working directory temporarily.""" | ||
old_dir = Path.cwd() | ||
os.chdir(new_dir) | ||
try: | ||
yield | ||
finally: | ||
os.chdir(old_dir) | ||
|
||
|
||
@pytest.fixture | ||
def uv_init_dir(tmp_path: Path) -> None: | ||
subprocess.run(["uv", "init"], cwd=tmp_path, check=True) | ||
return tmp_path | ||
|
||
|
||
class TestDeptry: | ||
def test_dependency_added(self, uv_init_dir: Path): | ||
# Act | ||
with change_cwd(uv_init_dir): | ||
deptry() | ||
|
||
# Assert | ||
(dev_dep,) = _get_dev_deps(uv_init_dir) | ||
assert dev_dep.startswith("deptry>=") | ||
|
||
def test_stdout(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): | ||
# Act | ||
with change_cwd(uv_init_dir): | ||
deptry() | ||
|
||
# Assert | ||
out, _ = capfd.readouterr() | ||
assert out == "✔ Ensuring deptry is a development dependency\n" | ||
|
||
def test_run_deptry_fail(self, uv_init_dir: Path): | ||
# Arrange | ||
f = uv_init_dir / "bad.py" | ||
f.write_text("import broken_dependency") | ||
|
||
# Act | ||
with change_cwd(uv_init_dir): | ||
deptry() | ||
|
||
# Assert | ||
with pytest.raises(subprocess.CalledProcessError): | ||
subprocess.run(["deptry", "."], cwd=uv_init_dir, check=True) | ||
|
||
def test_run_deptry_pass(self, uv_init_dir: Path): | ||
# Arrange | ||
f = uv_init_dir / "good.py" | ||
f.write_text("import sys") | ||
|
||
# Act | ||
with change_cwd(uv_init_dir): | ||
deptry() | ||
|
||
# Assert | ||
subprocess.run(["deptry", "."], cwd=uv_init_dir, check=True) | ||
|
||
def test_cli(self, uv_init_dir: Path): | ||
subprocess.run(["usethis", "tool", "deptry"], cwd=uv_init_dir, check=True) | ||
|
||
|
||
def _get_dev_deps(proj_dir: Path) -> list[str]: | ||
pyproject = tomlkit.parse((proj_dir / "pyproject.toml").read_text()) | ||
dev_deps = pyproject["tool"]["uv"]["dev-dependencies"] | ||
return TypeAdapter(list[str]).validate_python(dev_deps) |