diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3f55d3..b83222f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,8 +15,8 @@ jobs: - name: Setup git user config run: | - git config --global user.name github-actions[bot] - git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com + git config --global user.name placeholder + git config --global user.email placeholder@example.com - name: "Set up uv" uses: astral-sh/setup-uv@f3bcaebff5eace81a1c062af9f9011aae482ca9d # v3.1.7 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bf906fb..0600fee 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/abravalheri/validate-pyproject - rev: v0.21 + rev: "v0.21" hooks: - id: validate-pyproject additional_dependencies: ["validate-pyproject-schema-store[all]"] diff --git a/pyproject.toml b/pyproject.toml index 1281c54..a6f30e9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,16 +28,17 @@ dev-dependencies = [ "pytest-md>=0.2.0", "pytest-emoji>=0.2.0", "deptry>=0.20.0", - "pre-commit>=4.0.1", "ruff>=0.7.0", "pytest-cov>=5.0.0", "gitpython>=3.1.43", + "pre-commit>=4.0.1", ] [tool.coverage.run] source = ["src"] omit = ["*/pytest-of-*/*"] + [tool.ruff] src = ["src"] line-length = 88 diff --git a/src/usethis/_pre_commit/core.py b/src/usethis/_pre_commit/core.py index 80d8648..0020986 100644 --- a/src/usethis/_pre_commit/core.py +++ b/src/usethis/_pre_commit/core.py @@ -28,7 +28,11 @@ ] -def make_pre_commit_config() -> None: +def ensure_pre_commit_config() -> None: + if (Path.cwd() / ".pre-commit-config.yaml").exists(): + # Early exit; the file already exists + return + console.print("✔ Creating .pre-commit-config.yaml file", style="green") try: pkg_version = get_github_latest_tag("abravalheri", "validate-pyproject") @@ -40,34 +44,16 @@ def make_pre_commit_config() -> None: (Path.cwd() / ".pre-commit-config.yaml").write_text(yaml_contents) -def ensure_pre_commit_config() -> None: +def remove_pre_commit_config() -> None: if not (Path.cwd() / ".pre-commit-config.yaml").exists(): - make_pre_commit_config() - - -def delete_hook(name: str) -> None: - path = Path.cwd() / ".pre-commit-config.yaml" - - with path.open(mode="r") as f: - content, sequence_ind, offset_ind = load_yaml_guess_indent(f) - - yaml = ruamel.yaml.YAML(typ="rt") - yaml.indent(mapping=sequence_ind, sequence=sequence_ind, offset=offset_ind) - - # search across the repos for any hooks with ID equal to name - for repo in content["repos"]: - for hook in repo["hooks"]: - if hook["id"] == name: - repo["hooks"].remove(hook) + # Early exit; the file already doesn't exist + return - # if repo has no hooks, remove it - if not repo["hooks"]: - content["repos"].remove(repo) - - yaml.dump(content, path) + console.print("✔ Removing .pre-commit-config.yaml file", style="green") + (Path.cwd() / ".pre-commit-config.yaml").unlink() -def add_single_hook(config: PreCommitRepoConfig) -> None: +def add_hook(config: PreCommitRepoConfig) -> None: path = Path.cwd() / ".pre-commit-config.yaml" with path.open(mode="r") as f: @@ -82,10 +68,14 @@ def add_single_hook(config: PreCommitRepoConfig) -> None: # Get an ordered list of the hooks already in the file existing_hooks = get_hook_names(path.parent) + if not existing_hooks: + raise NotImplementedError + # Get the precendents, i.e. hooks occuring before the new hook - hook_idx = _HOOK_ORDER.index(hook_name) - if hook_idx == -1: - raise ValueError(f"Hook {hook_name} not recognized") + try: + hook_idx = _HOOK_ORDER.index(hook_name) + except ValueError: + raise NotImplementedError(f"Hook '{hook_name}' not recognized") precedents = _HOOK_ORDER[:hook_idx] # Find the last of the precedents in the existing hooks @@ -111,6 +101,28 @@ def add_single_hook(config: PreCommitRepoConfig) -> None: yaml.dump(content, path) +def remove_hook(name: str) -> None: + path = Path.cwd() / ".pre-commit-config.yaml" + + with path.open(mode="r") as f: + content, sequence_ind, offset_ind = load_yaml_guess_indent(f) + + yaml = ruamel.yaml.YAML(typ="rt") + yaml.indent(mapping=sequence_ind, sequence=sequence_ind, offset=offset_ind) + + # search across the repos for any hooks with ID equal to name + for repo in content["repos"]: + for hook in repo["hooks"]: + if hook["id"] == name: + repo["hooks"].remove(hook) + + # if repo has no hooks, remove it + if not repo["hooks"]: + content["repos"].remove(repo) + + yaml.dump(content, path) + + def get_hook_names(path: Path) -> list[str]: yaml = ruamel.yaml.YAML() with (path / ".pre-commit-config.yaml").open(mode="r") as f: @@ -140,3 +152,12 @@ def install_pre_commit() -> None: check=True, stdout=subprocess.DEVNULL, ) + + +def uninstall_pre_commit() -> None: + console.print("✔ Uninstalling pre-commit hooks", style="green") + subprocess.run( + ["uv", "run", "pre-commit", "uninstall"], + check=True, + stdout=subprocess.DEVNULL, + ) diff --git a/src/usethis/_tool.py b/src/usethis/_tool.py index cb6adaf..76a492a 100644 --- a/src/usethis/_tool.py +++ b/src/usethis/_tool.py @@ -9,9 +9,10 @@ from usethis import console from usethis._pre_commit.config import HookConfig, PreCommitRepoConfig from usethis._pre_commit.core import ( - add_single_hook, + add_hook, ensure_pre_commit_config, get_hook_names, + remove_hook, ) from usethis._pyproject.config import PyProjectConfig from usethis._uv.deps import get_dev_deps @@ -71,12 +72,31 @@ def add_pre_commit_repo_config(self) -> None: ) first_time_adding = False - add_single_hook( + add_hook( PreCommitRepoConfig( repo=repo_config.repo, rev=repo_config.rev, hooks=[hook] ) ) + def remove_pre_commit_repo_config(self) -> None: + """Remove the tool's pre-commit configuration.""" + try: + repo_config = self.get_pre_commit_repo_config() + except NotImplementedError: + return + + # Remove the config for this specific tool. + first_removal = True + for hook in repo_config.hooks: + if hook.id in get_hook_names(Path.cwd()): + if first_removal: + console.print( + f"✔ Removing {self.name} config from .pre-commit-config.yaml", + style="green", + ) + first_removal = False + remove_hook(hook.id) + def add_pyproject_config(self) -> None: """Add the tool's pyproject.toml configuration.""" @@ -98,9 +118,7 @@ def add_pyproject_config(self) -> None: # The configuration is already present. return - console.print( - f"✔ Adding {self.pypi_name} configuration to pyproject.toml", style="green" - ) + console.print(f"✔ Adding {self.name} config to pyproject.toml", style="green") # The old configuration should be kept for all ID keys except the final/deepest # one which shouldn't exist anyway since we checked as much, above. For example, @@ -110,6 +128,45 @@ def add_pyproject_config(self) -> None: (Path.cwd() / "pyproject.toml").write_text(tomlkit.dumps(pyproject)) + def remove_pyproject_config(self) -> None: + """Remove the tool's pyproject.toml configuration.""" + try: + config = self.get_pyproject_config() + except NotImplementedError: + return + + pyproject = tomlkit.parse((Path.cwd() / "pyproject.toml").read_text()) + + # Exit early if the configuration is not present. + try: + p = pyproject + for key in config.id_keys: + p = p[key] + except KeyError: + # The configuration is not present. + return + + console.print( + f"✔ Removing {self.name} config from pyproject.toml", + style="green", + ) + + # Remove the configuration. + p = pyproject + for key in config.id_keys[:-1]: + p = p[key] + del p[config.id_keys[-1]] + + # Cleanup: any empty sections should be removed. + for idx in range(len(config.id_keys) - 1): + p = pyproject + for key in config.id_keys[: idx + 1]: + p = p[key] + if not p: + del p + + (Path.cwd() / "pyproject.toml").write_text(tomlkit.dumps(pyproject)) + def ensure_dev_dep(self) -> None: """Add the tool as a development dependency, if it is not already.""" console.print( @@ -117,6 +174,18 @@ def ensure_dev_dep(self) -> None: ) subprocess.run(["uv", "add", "--dev", "--quiet", self.pypi_name], check=True) + def remove_dev_dep(self) -> None: + """Remove the tool as a development dependency, if it is present.""" + if self.pypi_name not in get_dev_deps(Path.cwd()): + # Early exit; the tool is already not a dev dependency. + return + + console.print( + f"✔ Removing {self.pypi_name} as a development dependency", + style="green", + ) + subprocess.run(["uv", "remove", "--dev", "--quiet", self.pypi_name], check=True) + class PreCommitTool(Tool): @property diff --git a/src/usethis/tool.py b/src/usethis/tool.py index fcfd55b..7b09900 100644 --- a/src/usethis/tool.py +++ b/src/usethis/tool.py @@ -1,6 +1,11 @@ import typer -from usethis._pre_commit.core import ensure_pre_commit_config, install_pre_commit +from usethis._pre_commit.core import ( + ensure_pre_commit_config, + install_pre_commit, + remove_pre_commit_config, + uninstall_pre_commit, +) from usethis._tool import ALL_TOOLS, DeptryTool, PreCommitTool, RuffTool app = typer.Typer(help="Add and configure development tools, e.g. linters") @@ -9,30 +14,73 @@ @app.command( help="Use the pre-commit framework to manage and maintain pre-commit hooks." ) -def pre_commit() -> None: +def pre_commit( + remove: bool = typer.Option( + False, "--remove", help="Remove pre-commit instead of adding it." + ), +) -> None: + _pre_commit(remove=remove) + + +def _pre_commit(*, remove: bool = False) -> None: tool = PreCommitTool() - tool.ensure_dev_dep() - ensure_pre_commit_config() - for tool in ALL_TOOLS: - if tool.is_used(): - tool.add_pre_commit_repo_config() - install_pre_commit() + + if not remove: + tool.ensure_dev_dep() + ensure_pre_commit_config() + for tool in ALL_TOOLS: + if tool.is_used(): + tool.add_pre_commit_repo_config() + install_pre_commit() + else: + uninstall_pre_commit() + remove_pre_commit_config() + tool.remove_dev_dep() @app.command( help="Use the deptry linter: avoid missing or superfluous dependency declarations." ) -def deptry() -> None: +def deptry( + remove: bool = typer.Option( + False, "--remove", help="Remove deptry instead of adding it." + ), +) -> None: + _deptry(remove=remove) + + +def _deptry(*, remove: bool = False) -> None: tool = DeptryTool() - tool.ensure_dev_dep() - if PreCommitTool().is_used(): - tool.add_pre_commit_repo_config() + + if not remove: + tool.ensure_dev_dep() + if PreCommitTool().is_used(): + tool.add_pre_commit_repo_config() + else: + if PreCommitTool().is_used(): + tool.remove_pre_commit_repo_config() + tool.remove_dev_dep() @app.command(help="Use ruff: an extremely fast Python linter and code formatter.") -def ruff() -> None: +def ruff( + remove: bool = typer.Option( + False, "--remove", help="Remove ruff instead of adding it." + ), +) -> None: + _ruff(remove=remove) + + +def _ruff(*, remove: bool = False) -> None: tool = RuffTool() - tool.ensure_dev_dep() - tool.add_pyproject_config() - if PreCommitTool().is_used(): - tool.add_pre_commit_repo_config() + + if not remove: + tool.ensure_dev_dep() + tool.add_pyproject_config() + if PreCommitTool().is_used(): + tool.add_pre_commit_repo_config() + else: + if PreCommitTool().is_used(): + tool.remove_pre_commit_repo_config() + tool.remove_pyproject_config() + tool.remove_dev_dep() diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..87d0edb --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,18 @@ +import subprocess +from pathlib import Path + +import pytest +from git import Repo + + +@pytest.fixture(scope="function") +def uv_init_dir(tmp_path: Path) -> Path: + subprocess.run(["uv", "init", "--lib"], cwd=tmp_path, check=True) + return tmp_path + + +@pytest.fixture(scope="function") +def uv_init_repo_dir(tmp_path: Path) -> Path: + subprocess.run(["uv", "init", "--lib"], cwd=tmp_path, check=True) + Repo.init(tmp_path) + return tmp_path diff --git a/tests/usethis/_pre_commit/test_core.py b/tests/usethis/_pre_commit/test_core.py new file mode 100644 index 0000000..2634c4a --- /dev/null +++ b/tests/usethis/_pre_commit/test_core.py @@ -0,0 +1,250 @@ +from pathlib import Path + +import pytest +import requests + +from usethis._pre_commit.config import HookConfig, PreCommitRepoConfig +from usethis._pre_commit.core import ( + _VALIDATEPYPROJECT_VERSION, + DuplicatedHookNameError, + add_hook, + ensure_pre_commit_config, + get_hook_names, + remove_hook, + remove_pre_commit_config, +) +from usethis._test import change_cwd + + +class TestEnsurePreCommitConfig: + def test_exists(self, uv_init_dir: Path): + # Act + with change_cwd(uv_init_dir): + ensure_pre_commit_config() + + # Assert + contents = (uv_init_dir / ".pre-commit-config.yaml").read_text() + assert contents == ( + f""" +repos: + - repo: https://github.com/abravalheri/validate-pyproject + rev: "{_VALIDATEPYPROJECT_VERSION}" + hooks: + - id: validate-pyproject + additional_dependencies: ["validate-pyproject-schema-store[all]"] +""" + ) + + def test_fallback(self, uv_init_dir: Path, monkeypatch: pytest.MonkeyPatch): + # Arrange + def mock_get(*args, **kwargs): + class MockResponse: + def raise_for_status(self): + raise requests.exceptions.HTTPError("Failed to fetch tags") + + return MockResponse() + + monkeypatch.setattr("requests.get", mock_get) + + # Act + with change_cwd(uv_init_dir): + ensure_pre_commit_config() + + # Assert + contents = (uv_init_dir / ".pre-commit-config.yaml").read_text() + assert contents == ( + f""" +repos: + - repo: https://github.com/abravalheri/validate-pyproject + rev: "{_VALIDATEPYPROJECT_VERSION}" + hooks: + - id: validate-pyproject + additional_dependencies: ["validate-pyproject-schema-store[all]"] +""" + ) + + def test_message(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): + # Act + with change_cwd(uv_init_dir): + ensure_pre_commit_config() + + # Assert + out, _ = capfd.readouterr() + assert out == "✔ Creating .pre-commit-config.yaml file\n" + + def test_already_exists(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): + # Arrange + (uv_init_dir / ".pre-commit-config.yaml").touch() + + # Act + with change_cwd(uv_init_dir): + ensure_pre_commit_config() + + # Assert + out, _ = capfd.readouterr() + assert out == "" + assert (uv_init_dir / ".pre-commit-config.yaml").read_text() == "" + + +class TestRemovePreCommitConfig: + def test_exists(self, uv_init_dir: Path): + # Arrange + (uv_init_dir / ".pre-commit-config.yaml").touch() + + # Act + with change_cwd(uv_init_dir): + remove_pre_commit_config() + + # Assert + assert not (uv_init_dir / ".pre-commit-config.yaml").exists() + + def test_message(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): + # Arrange + (uv_init_dir / ".pre-commit-config.yaml").touch() + + # Act + with change_cwd(uv_init_dir): + remove_pre_commit_config() + + # Assert + out, _ = capfd.readouterr() + assert out == "✔ Removing .pre-commit-config.yaml file\n" + + def test_already_missing( + self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str] + ): + # Act + with change_cwd(uv_init_dir): + remove_pre_commit_config() + + # Assert + out, _ = capfd.readouterr() + assert out == "" + assert not (uv_init_dir / ".pre-commit-config.yaml").exists() + + def test_does_not_exist(self, uv_init_dir: Path): + # Act + with change_cwd(uv_init_dir): + remove_pre_commit_config() + + # Assert + assert not (uv_init_dir / ".pre-commit-config.yaml").exists() + + +class TestAddHook: + def test_unregistered_id(self, tmp_path: Path): + (tmp_path / ".pre-commit-config.yaml").write_text(""" +repos: + - repo: foo + hooks: + - id: bar +""") + with ( + change_cwd(tmp_path), + pytest.raises(NotImplementedError, match="Hook 'foo' not recognized"), + ): + add_hook( + PreCommitRepoConfig( + repo="foo", rev="foo", hooks=[HookConfig(id="foo", name="foo")] + ) + ) + + +class TestRemoveHook: + def test_empty(self, tmp_path: Path): + (tmp_path / ".pre-commit-config.yaml").write_text("repos: []\n") + with change_cwd(tmp_path): + remove_hook("foo") + assert (tmp_path / ".pre-commit-config.yaml").read_text() == "repos: []\n" + + def test_single(self, tmp_path: Path): + (tmp_path / ".pre-commit-config.yaml").write_text( + """repos: + - repo: foo + hooks: + - id: bar +""" + ) + with change_cwd(tmp_path): + remove_hook("bar") + assert (tmp_path / ".pre-commit-config.yaml").read_text() == "repos: []\n" + + def test_multihooks(self, tmp_path: Path): + (tmp_path / ".pre-commit-config.yaml").write_text( + """repos: + - repo: foo # comment + hooks: + - id: bar + - id: baz +""" + ) + with change_cwd(tmp_path): + remove_hook("bar") + assert (tmp_path / ".pre-commit-config.yaml").read_text() == ( + """repos: + - repo: foo # comment + hooks: + - id: baz +""" + ) + + +class TestGetHookNames: + def test_empty(self, tmp_path: Path): + (tmp_path / ".pre-commit-config.yaml").write_text("repos: []\n") + assert get_hook_names(tmp_path) == [] + + def test_single(self, tmp_path: Path): + (tmp_path / ".pre-commit-config.yaml").write_text( + """ +repos: + - repo: foo + hooks: + - id: bar +""" + ) + assert get_hook_names(tmp_path) == ["bar"] + + def test_multihooks(self, tmp_path: Path): + (tmp_path / ".pre-commit-config.yaml").write_text( + """ +repos: + - repo: foo + hooks: + - id: bar + - id: baz +""" + ) + assert get_hook_names(tmp_path) == ["bar", "baz"] + + def test_multirepo(self, tmp_path: Path): + (tmp_path / ".pre-commit-config.yaml").write_text( + """ +repos: + - repo: foo + hooks: + - id: bar + - repo: baz + hooks: + - id: qux +""" + ) + assert get_hook_names(tmp_path) == ["bar", "qux"] + + def test_duplicated_raises(self, tmp_path: Path): + (tmp_path / ".pre-commit-config.yaml").write_text( + """ +repos: + - repo: foo + hooks: + - id: bar + - repo: baz + hooks: + - id: bar +""" + ) + + with pytest.raises( + DuplicatedHookNameError, match="Hook name 'bar' is duplicated" + ): + get_hook_names(tmp_path) diff --git a/tests/usethis/test_pre_commit.py b/tests/usethis/test_pre_commit.py deleted file mode 100644 index ed3704f..0000000 --- a/tests/usethis/test_pre_commit.py +++ /dev/null @@ -1,110 +0,0 @@ -from pathlib import Path - -import pytest - -from usethis._pre_commit.core import ( - DuplicatedHookNameError, - delete_hook, - get_hook_names, -) -from usethis._test import change_cwd - - -class TestDeleteHook: - def test_empty(self, tmp_path: Path): - (tmp_path / ".pre-commit-config.yaml").write_text("repos: []\n") - with change_cwd(tmp_path): - delete_hook("foo") - assert (tmp_path / ".pre-commit-config.yaml").read_text() == "repos: []\n" - - def test_single(self, tmp_path: Path): - (tmp_path / ".pre-commit-config.yaml").write_text( - """repos: - - repo: foo - hooks: - - id: bar -""" - ) - with change_cwd(tmp_path): - delete_hook("bar") - assert (tmp_path / ".pre-commit-config.yaml").read_text() == "repos: []\n" - - def test_multihooks(self, tmp_path: Path): - (tmp_path / ".pre-commit-config.yaml").write_text( - """repos: - - repo: foo # comment - hooks: - - id: bar - - id: baz -""" - ) - with change_cwd(tmp_path): - delete_hook("bar") - assert (tmp_path / ".pre-commit-config.yaml").read_text() == ( - """repos: - - repo: foo # comment - hooks: - - id: baz -""" - ) - - -class TestGetHookNames: - def test_empty(self, tmp_path: Path): - (tmp_path / ".pre-commit-config.yaml").write_text("repos: []\n") - assert get_hook_names(tmp_path) == [] - - def test_single(self, tmp_path: Path): - (tmp_path / ".pre-commit-config.yaml").write_text( - """ -repos: - - repo: foo - hooks: - - id: bar -""" - ) - assert get_hook_names(tmp_path) == ["bar"] - - def test_multihooks(self, tmp_path: Path): - (tmp_path / ".pre-commit-config.yaml").write_text( - """ -repos: - - repo: foo - hooks: - - id: bar - - id: baz -""" - ) - assert get_hook_names(tmp_path) == ["bar", "baz"] - - def test_multirepo(self, tmp_path: Path): - (tmp_path / ".pre-commit-config.yaml").write_text( - """ -repos: - - repo: foo - hooks: - - id: bar - - repo: baz - hooks: - - id: qux -""" - ) - assert get_hook_names(tmp_path) == ["bar", "qux"] - - def test_duplicated_raises(self, tmp_path: Path): - (tmp_path / ".pre-commit-config.yaml").write_text( - """ -repos: - - repo: foo - hooks: - - id: bar - - repo: baz - hooks: - - id: bar -""" - ) - - with pytest.raises( - DuplicatedHookNameError, match="Hook name 'bar' is duplicated" - ): - get_hook_names(tmp_path) diff --git a/tests/usethis/test_tool.py b/tests/usethis/test_tool.py index 9799af8..73c3dbb 100644 --- a/tests/usethis/test_tool.py +++ b/tests/usethis/test_tool.py @@ -2,7 +2,6 @@ from pathlib import Path import pytest -from git import Repo from usethis._pre_commit.core import ( _HOOK_ORDER, @@ -11,27 +10,14 @@ ) from usethis._test import change_cwd from usethis._tool import ALL_TOOLS, get_dev_deps -from usethis.tool import deptry, pre_commit, ruff - - -@pytest.fixture(scope="function") -def uv_init_dir(tmp_path: Path) -> Path: - subprocess.run(["uv", "init"], cwd=tmp_path, check=True) - return tmp_path - - -@pytest.fixture(scope="function") -def uv_init_repo_dir(tmp_path: Path) -> Path: - subprocess.run(["uv", "init"], cwd=tmp_path, check=True) - Repo.init(tmp_path) - return tmp_path +from usethis.tool import _deptry, _pre_commit, _ruff class TestToolPreCommit: def test_dependency_added(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir): - pre_commit() + _pre_commit() # Assert (dev_dep,) = get_dev_deps(uv_init_dir) @@ -40,7 +26,7 @@ def test_dependency_added(self, uv_init_dir: Path): def test_stdout(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): # Act with change_cwd(uv_init_dir): - pre_commit() + _pre_commit() # Assert out, _ = capfd.readouterr() @@ -53,7 +39,7 @@ def test_stdout(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): def test_config_file_exists(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir): - pre_commit() + _pre_commit() # Assert assert (uv_init_dir / ".pre-commit-config.yaml").exists() @@ -61,7 +47,7 @@ def test_config_file_exists(self, uv_init_dir: Path): def test_config_file_contents(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir): - pre_commit() + _pre_commit() # Assert contents = (uv_init_dir / ".pre-commit-config.yaml").read_text() @@ -89,7 +75,7 @@ def test_already_exists(self, uv_init_repo_dir: Path): # Act with change_cwd(uv_init_repo_dir): - pre_commit() + _pre_commit() # Assert contents = (uv_init_repo_dir / ".pre-commit-config.yaml").read_text() @@ -105,7 +91,7 @@ def test_already_exists(self, uv_init_repo_dir: Path): def test_bad_commit(self, uv_init_repo_dir: Path): # Act with change_cwd(uv_init_repo_dir): - pre_commit() + _pre_commit() subprocess.run(["git", "add", "."], cwd=uv_init_repo_dir, check=True) subprocess.run( ["git", "commit", "-m", "Good commit"], cwd=uv_init_repo_dir, check=True @@ -153,7 +139,7 @@ class TestDeptry: def test_dependency_added(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir): - deptry() + _deptry() # Assert (dev_dep,) = get_dev_deps(uv_init_dir) @@ -162,7 +148,7 @@ def test_dependency_added(self, uv_init_dir: Path): def test_stdout(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): # Act with change_cwd(uv_init_dir): - deptry() + _deptry() # Assert out, _ = capfd.readouterr() @@ -175,7 +161,7 @@ def test_run_deptry_fail(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir): - deptry() + _deptry() # Assert with pytest.raises(subprocess.CalledProcessError): @@ -188,7 +174,7 @@ def test_run_deptry_pass(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir): - deptry() + _deptry() # Assert subprocess.run(["deptry", "."], cwd=uv_init_dir, check=True) @@ -201,8 +187,8 @@ def test_pre_commit_after( ): # Act with change_cwd(uv_init_dir): - deptry() - pre_commit() + _deptry() + _pre_commit() # Assert # 1. File exists @@ -245,8 +231,8 @@ def test_pre_commit_first( ): # Act with change_cwd(uv_init_dir): - pre_commit() - deptry() + _pre_commit() + _deptry() # Assert # 1. File exists @@ -289,7 +275,7 @@ class TestRuff: def test_dependency_added(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir): - ruff() + _ruff() # Assert (dev_dep,) = get_dev_deps(uv_init_dir) @@ -298,13 +284,13 @@ def test_dependency_added(self, uv_init_dir: Path): def test_stdout(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): # Act with change_cwd(uv_init_dir): - ruff() + _ruff() # Assert out, _ = capfd.readouterr() assert out == ( "✔ Ensuring ruff is a development dependency\n" - "✔ Adding ruff configuration to pyproject.toml\n" + "✔ Adding ruff config to pyproject.toml\n" ) def test_cli(self, uv_init_dir: Path): @@ -315,8 +301,8 @@ def test_pre_commit_first( ): # Act with change_cwd(uv_init_dir): - ruff() - pre_commit() + _ruff() + _pre_commit() # Assert assert "ruff-format" in get_hook_names(uv_init_dir)