From 70aca39b4ed7e82e5876a2b94549b3a7d0f94cbd Mon Sep 17 00:00:00 2001 From: Dane Hillard Date: Mon, 22 Jun 2026 09:33:18 -0400 Subject: [PATCH 1/2] Prep 0.2.0 release - Fix independent Click usage now that Click is vendored in Typer - Fix deprecated usage of `isolated_filesystem` in tests - Drop Python 3.10 support --- .github/workflows/packaging.yml | 2 - docs/CHANGELOG.md | 11 ++ pyproject.toml | 28 +++-- src/repo_man/commands/edit.py | 4 +- test/test_add.py | 185 ++++++++++++++++++-------------- test/test_edit.py | 29 ++--- test/test_implode.py | 42 ++++---- test/test_init.py | 70 ++++++------ test/test_list_repos.py | 130 ++++++++++++---------- test/test_remove.py | 98 +++++++++-------- test/test_sniff.py | 86 +++++++++------ test/test_types.py | 91 +++++++++------- test/test_utils.py | 20 ++-- 13 files changed, 441 insertions(+), 355 deletions(-) diff --git a/.github/workflows/packaging.yml b/.github/workflows/packaging.yml index aae6f9b..f3d2754 100644 --- a/.github/workflows/packaging.yml +++ b/.github/workflows/packaging.yml @@ -66,8 +66,6 @@ jobs: toxenv: "py312" - version: "3.11" toxenv: "py311" - - version: "3.10" - toxenv: "py310" steps: - uses: actions/checkout@v6 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c97f388..be63631 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [0.2.0] - 2026-06-22 + +### Fixed + +- Fix independent use of Click, which is now vendored in Typer +- Fix deprecated Typer `isolated_filesystem` usage in tests + +### Removed + +- Remove support for Python 3.10 + ### Added - Add support for Python 3.14 diff --git a/pyproject.toml b/pyproject.toml index 8628586..0866520 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,13 @@ [build-system] -requires = ["setuptools", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["uv_build>=0.11.23,<0.12.0"] +build-backend = "uv_build" [project] -requires-python = ">=3.10" +requires-python = ">=3.11" name = "repo-man" -version = "0.1.2" +version = "0.2.0" description = "Manage repositories of a variety of different types." +readme = "README.md" authors = [ { name = "Dane Hillard", email = "github@danehillard.com" } ] @@ -15,7 +16,6 @@ classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Programming Language :: Python", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", @@ -24,19 +24,15 @@ classifiers = [ "Programming Language :: Python :: 3 :: Only", ] dependencies = [ - "typer>=0.12.5" + "click>=8.4.1", + "typer>=0.26.7", ] -dynamic = ["readme"] [project.urls] Documentation = "https://repo-man.readthedocs.org" Repository = "https://github.com/easy-as-python/repo-man" Issues = "https://github.com/easy-as-python/repo-man/issues" -[tool.setuptools.packages.find] -where = ["src"] -exclude = ["test*"] - [project.scripts] repo-man = "repo_man.cli:main" @@ -48,8 +44,8 @@ docs = [ "sphinx-autobuild", ] -[tool.setuptools.dynamic] -readme = { file = "README.md", content-type = "text/markdown" } +[tool.uv.build-backend] +module-name = "repo_man" ###################### # Tool configuration # @@ -76,7 +72,7 @@ select = [ [tool.mypy] strict = true -python_version = "3.10" +python_version = "3.11" warn_unused_configs = true show_error_context = true pretty = true @@ -93,7 +89,7 @@ source = ["repo_man"] branch = true [tool.coverage.report] -fail_under = 90.00 +fail_under = 95.00 show_missing = true skip_covered = true @@ -104,7 +100,7 @@ source = [ ] [tool.tox] -envlist = ["py310", "py311", "py312", "py313", "py314"] +env_list = ["py311", "py312", "py313", "py314"] isolated_build = true [tool.tox.env_run_base] diff --git a/src/repo_man/commands/edit.py b/src/repo_man/commands/edit.py index e2918eb..69e16ac 100644 --- a/src/repo_man/commands/edit.py +++ b/src/repo_man/commands/edit.py @@ -1,4 +1,4 @@ -import typer +import click from repo_man.consts import REPO_TYPES_CFG from repo_man.utils import ensure_config_file_exists @@ -9,4 +9,4 @@ def edit() -> None: ensure_config_file_exists() - typer.edit(filename=REPO_TYPES_CFG) + click.edit(filename=REPO_TYPES_CFG) diff --git a/test/test_add.py b/test/test_add.py index 80c8b50..70b66be 100644 --- a/test/test_add.py +++ b/test/test_add.py @@ -1,4 +1,5 @@ import configparser +import os from collections.abc import Callable from pathlib import Path @@ -7,129 +8,151 @@ from repo_man.cli import cli -def test_add_clean_confirm(runner: CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - (Path(".") / "some-repo").mkdir() - config = get_config() - result = runner.invoke(cli, ["add", "some-repo", "-t", "some-type"], input="Y\nY\n", obj=config) - assert result.exit_code == 0 - assert ( - result.output - == """No repo-man.cfg file found. Do you want to continue? [y/N]: Y +def test_add_clean_confirm( + runner: CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) + + config = get_config() + result = runner.invoke(cli, ["add", "some-repo", "-t", "some-type"], input="Y\nY\n", obj=config) + assert result.exit_code == 0 + assert ( + result.output + == """No repo-man.cfg file found. Do you want to continue? [y/N]: Y The following types are unknown and will be added: some-type Continue? [y/N]: Y """ - ) + ) - with open("repo-man.cfg") as config_file: - assert config_file.read() == """[some-type]\nknown = \n some-repo\n\n""" + with open("repo-man.cfg") as config_file: + assert config_file.read() == """[some-type]\nknown = \n some-repo\n\n""" -def test_add_clean_no_confirm_new_file(runner: CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - (Path(".") / "some-repo").mkdir() - config = get_config() - result = runner.invoke(cli, ["add", "some-repo", "-t", "some-type"], input="\n", obj=config) - assert result.exit_code == 1 - assert result.output == """No repo-man.cfg file found. Do you want to continue? [y/N]: \nAborted.\n""" +def test_add_clean_no_confirm_new_file( + runner: CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) + + config = get_config() + result = runner.invoke(cli, ["add", "some-repo", "-t", "some-type"], input="\n", obj=config) + assert result.exit_code == 1 + assert result.output == """No repo-man.cfg file found. Do you want to continue? [y/N]: \nAborted.\n""" -def test_add_with_existing_file(runner: CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] +def test_add_with_existing_file( + runner: CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) + + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = bar """ - ) - - (Path(".") / "some-repo").mkdir() - config = get_config() - result = runner.invoke(cli, ["add", "some-repo", "-t", "some-type"], input="Y\n", obj=config) - assert result.exit_code == 0 - assert ( - result.output - == """The following types are unknown and will be added:\n\n some-type\n\nContinue? [y/N]: Y\n""" ) - with open("repo-man.cfg") as config_file: - assert config_file.read() == """[foo]\nknown = \n bar\n\n[some-type]\nknown = \n some-repo\n\n""" + config = get_config() + result = runner.invoke(cli, ["add", "some-repo", "-t", "some-type"], input="Y\n", obj=config) + assert result.exit_code == 0 + assert ( + result.output + == """The following types are unknown and will be added:\n\n some-type\n\nContinue? [y/N]: Y\n""" + ) + + with open("repo-man.cfg") as config_file: + assert config_file.read() == """[foo]\nknown = \n bar\n\n[some-type]\nknown = \n some-repo\n\n""" def test_add_with_existing_file_and_type( - runner: CliRunner, get_config: Callable[[], configparser.ConfigParser] + runner: CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path ) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[some-type] + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) + + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[some-type] known = bar """ - ) + ) + + config = get_config() + result = runner.invoke(cli, ["add", "some-repo", "-t", "some-type"], obj=config) + assert result.exit_code == 0 + assert result.output == "" - (Path(".") / "some-repo").mkdir() - config = get_config() - result = runner.invoke(cli, ["add", "some-repo", "-t", "some-type"], obj=config) - assert result.exit_code == 0 - assert result.output == "" + with open("repo-man.cfg") as config_file: + assert config_file.read() == """[some-type]\nknown = \n bar\n some-repo\n\n""" - with open("repo-man.cfg") as config_file: - assert config_file.read() == """[some-type]\nknown = \n bar\n some-repo\n\n""" +def test_add_multiple_types( + runner: CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) -def test_add_multiple_types(runner: CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[some-type] + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[some-type] known = bar """ - ) - - (Path(".") / "some-repo").mkdir() - config = get_config() - result = runner.invoke( - cli, ["add", "some-repo", "-t", "some-type", "-t", "some-other-type"], input="Y\n", obj=config ) - assert result.exit_code == 0 - assert ( - result.output - == """The following types are unknown and will be added: + + config = get_config() + result = runner.invoke( + cli, ["add", "some-repo", "-t", "some-type", "-t", "some-other-type"], input="Y\n", obj=config + ) + assert result.exit_code == 0 + assert ( + result.output + == """The following types are unknown and will be added: some-other-type Continue? [y/N]: Y """ + ) + + with open("repo-man.cfg") as config_file: + assert ( + config_file.read() + == """[some-type]\nknown = \n bar\n some-repo\n\n[some-other-type]\nknown = \n some-repo\n\n""" ) - with open("repo-man.cfg") as config_file: - assert ( - config_file.read() - == """[some-type]\nknown = \n bar\n some-repo\n\n[some-other-type]\nknown = \n some-repo\n\n""" - ) +def test_add_no_action_needed( + runner: CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) -def test_add_no_action_needed(runner: CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[some-type] + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[some-type] known = some-repo """ - ) + ) - (Path(".") / "some-repo").mkdir() - config = get_config() - result = runner.invoke(cli, ["add", "some-repo", "-t", "some-type"], obj=config) - assert result.exit_code == 0 - assert result.output == "" + config = get_config() + result = runner.invoke(cli, ["add", "some-repo", "-t", "some-type"], obj=config) + assert result.exit_code == 0 + assert result.output == "" - with open("repo-man.cfg") as config_file: - assert config_file.read() == """[some-type]\nknown = \n some-repo\n\n""" + with open("repo-man.cfg") as config_file: + assert config_file.read() == """[some-type]\nknown = \n some-repo\n\n""" diff --git a/test/test_edit.py b/test/test_edit.py index e2e6f66..9d84fdd 100644 --- a/test/test_edit.py +++ b/test/test_edit.py @@ -1,3 +1,4 @@ +import os from pathlib import Path from unittest.mock import Mock, patch @@ -6,18 +7,20 @@ from repo_man.cli import cli -def test_edit_clean(runner: testing.CliRunner) -> None: - with runner.isolated_filesystem(): - result = runner.invoke(cli, ["edit"]) - assert result.exit_code == 1 - assert result.output == "No repo-man.cfg file found.\n" +def test_edit_clean(runner: testing.CliRunner, tmp_path: Path) -> None: + os.chdir(tmp_path) + result = runner.invoke(cli, ["edit"]) + assert result.exit_code == 1 + assert result.output == "No repo-man.cfg file found.\n" -@patch("repo_man.commands.edit.typer.edit") -def test_edit_when_config_present(mock_edit: Mock, runner: testing.CliRunner) -> None: - with runner.isolated_filesystem(): - Path("repo-man.cfg").touch() - result = runner.invoke(cli, ["edit"]) - assert result.exit_code == 0 - assert result.output == "" - mock_edit.assert_called_once_with(filename="repo-man.cfg") + +@patch("repo_man.commands.edit.click.edit") +def test_edit_when_config_present(mock_edit: Mock, runner: testing.CliRunner, tmp_path: Path) -> None: + os.chdir(tmp_path) + + Path("repo-man.cfg").touch() + result = runner.invoke(cli, ["edit"]) + assert result.exit_code == 0 + assert result.output == "" + mock_edit.assert_called_once_with(filename="repo-man.cfg") diff --git a/test/test_implode.py b/test/test_implode.py index ee44438..fa3bf24 100644 --- a/test/test_implode.py +++ b/test/test_implode.py @@ -1,3 +1,4 @@ +import os from pathlib import Path from typer import testing @@ -5,28 +6,31 @@ from repo_man.cli import cli -def test_implode_when_config_present_confirm(runner: testing.CliRunner) -> None: - with runner.isolated_filesystem(): - Path("repo-man.cfg").touch() +def test_implode_when_config_present_confirm(runner: testing.CliRunner, tmp_path: Path) -> None: + os.chdir(tmp_path) - result = runner.invoke(cli, ["implode", "."], input="Y\n") - assert result.exit_code == 0 - assert result.output == "Are you sure you want to do this? [y/N]: Y\n" - assert not Path("repo-man.cfg").exists() + Path("repo-man.cfg").touch() + result = runner.invoke(cli, ["implode", "."], input="Y\n") + assert result.exit_code == 0 + assert result.output == "Are you sure you want to do this? [y/N]: Y\n" + assert not Path("repo-man.cfg").exists() -def test_implode_when_config_not_present_confirm(runner: testing.CliRunner) -> None: - with runner.isolated_filesystem(): - result = runner.invoke(cli, ["implode", "."], input="Y\n") - assert result.exit_code == 0 - assert result.output == "Are you sure you want to do this? [y/N]: Y\n" +def test_implode_when_config_not_present_confirm(runner: testing.CliRunner, tmp_path: Path) -> None: + os.chdir(tmp_path) -def test_implode_when_config_present_no_confirm(runner: testing.CliRunner) -> None: - with runner.isolated_filesystem(): - Path("repo-man.cfg").touch() + result = runner.invoke(cli, ["implode", "."], input="Y\n") + assert result.exit_code == 0 + assert result.output == "Are you sure you want to do this? [y/N]: Y\n" - result = runner.invoke(cli, ["implode", "."], input="\n") - assert result.exit_code == 1 - assert result.output == """Are you sure you want to do this? [y/N]: \nAborted.\n""" - assert Path("repo-man.cfg").exists() + +def test_implode_when_config_present_no_confirm(runner: testing.CliRunner, tmp_path: Path) -> None: + os.chdir(tmp_path) + + Path("repo-man.cfg").touch() + + result = runner.invoke(cli, ["implode", "."], input="\n") + assert result.exit_code == 1 + assert result.output == """Are you sure you want to do this? [y/N]: \nAborted.\n""" + assert Path("repo-man.cfg").exists() diff --git a/test/test_init.py b/test/test_init.py index 9268350..1a962cd 100644 --- a/test/test_init.py +++ b/test/test_init.py @@ -1,3 +1,4 @@ +import os from pathlib import Path from typer import testing @@ -5,55 +6,56 @@ from repo_man.cli import cli -def test_init_clean(runner: testing.CliRunner) -> None: - with runner.isolated_filesystem(): - assert not Path("repo-man.cfg").exists() +def test_init_clean(runner: testing.CliRunner, tmp_path: Path) -> None: + os.chdir(tmp_path) - result = runner.invoke(cli, ["init", "."]) - assert result.exit_code == 0 - assert result.output == "" - assert Path("repo-man.cfg").exists() + assert not Path("repo-man.cfg").exists() + result = runner.invoke(cli, ["init", "."]) + assert result.exit_code == 0 + assert result.output == "" + assert Path("repo-man.cfg").exists() -def test_init_with_existing_confirm(runner: testing.CliRunner) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] + +def test_init_with_existing_confirm(runner: testing.CliRunner, tmp_path: Path) -> None: + os.chdir(tmp_path) + + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = bar """ - ) + ) - result = runner.invoke(cli, ["init", "."], input="Y") - assert result.exit_code == 0 - assert result.output == "repo-man.cfg file already exists. Overwrite with empty configuration? [y/N]: Y\n" + result = runner.invoke(cli, ["init", "."], input="Y") + assert result.exit_code == 0 + assert result.output == "repo-man.cfg file already exists. Overwrite with empty configuration? [y/N]: Y\n" - with open("repo-man.cfg") as config_file: - assert config_file.read() == "" + with open("repo-man.cfg") as config_file: + assert config_file.read() == "" -def test_init_with_existing_no_confirm(runner: testing.CliRunner) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] +def test_init_with_existing_no_confirm(runner: testing.CliRunner, tmp_path: Path) -> None: + os.chdir(tmp_path) + + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = bar """ - ) - - result = runner.invoke(cli, ["init", "."], input="\n") - assert result.exit_code == 1 - assert ( - result.output == "repo-man.cfg file already exists. Overwrite with empty configuration? [y/N]: \nAborted.\n" ) - with open("repo-man.cfg") as config_file: - assert ( - config_file.read() - == """[foo] + result = runner.invoke(cli, ["init", "."], input="\n") + assert result.exit_code == 1 + assert result.output == "repo-man.cfg file already exists. Overwrite with empty configuration? [y/N]: \nAborted.\n" + + with open("repo-man.cfg") as config_file: + assert ( + config_file.read() + == """[foo] known = bar """ - ) + ) diff --git a/test/test_list_repos.py b/test/test_list_repos.py index f9ce6e9..a2f2a85 100644 --- a/test/test_list_repos.py +++ b/test/test_list_repos.py @@ -1,5 +1,7 @@ import configparser +import os from collections.abc import Callable +from pathlib import Path from unittest.mock import Mock, patch from typer import testing @@ -7,43 +9,52 @@ from repo_man.cli import cli -def test_list_repos_clean(runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - config = get_config() - result = runner.invoke(cli, ["list", "-t", "all"], obj=config) - assert result.exit_code == 1 - assert result.output == "No repo-man.cfg file found.\n" +def test_list_repos_clean( + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + os.chdir(tmp_path) + + config = get_config() + result = runner.invoke(cli, ["list", "-t", "all"], obj=config) + assert result.exit_code == 1 + assert result.output == "No repo-man.cfg file found.\n" def test_list_repos_with_matches( - runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser] + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path ) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] + os.chdir(tmp_path) + + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-repo some-other-repo """ - ) - - config = get_config() - result = runner.invoke(cli, ["list", "-t", "all"], obj=config) - assert result.exit_code == 0 - assert ( - result.output - == """some-other-repo + ) + + config = get_config() + result = runner.invoke(cli, ["list", "-t", "all"], obj=config) + assert result.exit_code == 0 + assert ( + result.output + == """some-other-repo some-repo """ - ) + ) @patch("repo_man.commands.list_repos.click.echo_via_pager") def test_list_repos_when_long( - mock_echo_via_pager: Mock, runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser] + mock_echo_via_pager: Mock, + runner: testing.CliRunner, + get_config: Callable[[], configparser.ConfigParser], + tmp_path: Path, ) -> None: + os.chdir(tmp_path) + all_repos = """some-repo-1 some-repo-2 some-repo-3 @@ -73,29 +84,29 @@ def test_list_repos_when_long( config_list = "\n ".join(all_repos.split("\n")) - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - f"""[foo] + with open("repo-man.cfg", "w") as config_file: + config_file.write( + f"""[foo] known = {config_list} """ - ) + ) - config = get_config() - result = runner.invoke(cli, ["list", "-t", "all"], obj=config) - assert result.exit_code == 0 - mock_echo_via_pager.assert_called_once_with("\n".join(sorted(all_repos.split("\n")))) + config = get_config() + result = runner.invoke(cli, ["list", "-t", "all"], obj=config) + assert result.exit_code == 0 + mock_echo_via_pager.assert_called_once_with("\n".join(sorted(all_repos.split("\n")))) def test_list_repos_for_multiple_tags( - runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser] + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path ) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] + os.chdir(tmp_path) + + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-repo @@ -104,26 +115,27 @@ def test_list_repos_for_multiple_tags( some-other-repo """ - ) - - config = get_config() - result = runner.invoke(cli, ["list", "-t", "foo", "-t", "bar"], obj=config) - assert result.exit_code == 0 - assert ( - result.output - == """some-other-repo + ) + + config = get_config() + result = runner.invoke(cli, ["list", "-t", "foo", "-t", "bar"], obj=config) + assert result.exit_code == 0 + assert ( + result.output + == """some-other-repo some-repo """ - ) + ) def test_list_repos_when_invalid_type( - runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser] + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path ) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] + os.chdir(tmp_path) + + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-repo @@ -132,13 +144,13 @@ def test_list_repos_when_invalid_type( some-other-repo """ - ) - - config = get_config() - result = runner.invoke(cli, ["list", "-t", "baz"], obj=config) - assert result.exit_code == 2 - print(result.output) - assert "│ Invalid value: Invalid repository type 'baz'. Valid types are:" in result.output - assert "│ all" in result.output - assert "│ foo" in result.output - assert "│ bar" in result.output + ) + + config = get_config() + result = runner.invoke(cli, ["list", "-t", "baz"], obj=config) + assert result.exit_code == 2 + print(result.output) + assert "│ Invalid value: Invalid repository type 'baz'. Valid types are:" in result.output + assert "│ all" in result.output + assert "│ foo" in result.output + assert "│ bar" in result.output diff --git a/test/test_remove.py b/test/test_remove.py index 461813f..709f659 100644 --- a/test/test_remove.py +++ b/test/test_remove.py @@ -1,4 +1,5 @@ import configparser +import os from collections.abc import Callable from pathlib import Path @@ -7,68 +8,73 @@ from repo_man.cli import cli -def test_remove_clean(runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - Path("some-repo").mkdir() +def test_remove_clean( + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-repo """ - ) + ) - config = get_config() - result = runner.invoke(cli, ["remove", "-t", "foo", "some-repo"], obj=config) - assert result.exit_code == 0 - assert result.output == "" + config = get_config() + result = runner.invoke(cli, ["remove", "-t", "foo", "some-repo"], obj=config) + assert result.exit_code == 0 + assert result.output == "" - with open("repo-man.cfg") as config_file: - assert config_file.read() == "[foo]\nknown = \n\n" + with open("repo-man.cfg") as config_file: + assert config_file.read() == "[foo]\nknown = \n\n" def test_remove_when_invalid_type( - runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser] + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path ) -> None: - with runner.isolated_filesystem(): - Path("some-repo").mkdir() + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-repo """ - ) - - config = get_config() - result = runner.invoke(cli, ["remove", "-t", "bar", "some-repo"], obj=config) - print(result.output) - assert result.exit_code == 2 - assert "│ Invalid value: Invalid repository type 'bar'. Valid types are:" in result.output - assert "│ all" in result.output - assert "│ foo" in result.output - - with open("repo-man.cfg") as config_file: - assert ( - config_file.read() - == """[foo] + ) + + config = get_config() + result = runner.invoke(cli, ["remove", "-t", "bar", "some-repo"], obj=config) + print(result.output) + assert result.exit_code == 2 + assert "│ Invalid value: Invalid repository type 'bar'. Valid types are:" in result.output + assert "│ all" in result.output + assert "│ foo" in result.output + + with open("repo-man.cfg") as config_file: + assert ( + config_file.read() + == """[foo] known = some-repo """ - ) + ) def test_remove_when_unused_type( - runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser] + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path ) -> None: - with runner.isolated_filesystem(): - Path("some-repo").mkdir() + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-repo @@ -76,11 +82,9 @@ def test_remove_when_unused_type( known = some-other-repo """ - ) - - config = get_config() - result = runner.invoke(cli, ["remove", "-t", "bar", "some-repo"], obj=config) - assert result.exit_code == 1 - assert ( - result.output == """Repository 'some-repo' is not configured for type 'bar'. Continue? [y/N]:Aborted.\n """ ) + + config = get_config() + result = runner.invoke(cli, ["remove", "-t", "bar", "some-repo"], obj=config) + assert result.exit_code == 1 + assert result.output == """Repository 'some-repo' is not configured for type 'bar'. Continue? [y/N]:Aborted.\n """ diff --git a/test/test_sniff.py b/test/test_sniff.py index e6c2037..651f71d 100644 --- a/test/test_sniff.py +++ b/test/test_sniff.py @@ -1,4 +1,5 @@ import configparser +import os from collections.abc import Callable from pathlib import Path @@ -7,11 +8,14 @@ from repo_man.cli import cli -def test_known(runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] +def test_known(runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) + + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-repo @@ -24,42 +28,54 @@ def test_known(runner: testing.CliRunner, get_config: Callable[[], configparser. yet-another-repo """ - ) + ) + + config = get_config() + config.read("repo-man.cfg") - config = get_config() - config.read("repo-man.cfg") + result = runner.invoke(cli, ["sniff", "--known"], obj=config) + assert result.exit_code == 0 + assert result.output == "bar\nfoo\n" - result = runner.invoke(cli, ["sniff", "--known"], obj=config) - assert result.exit_code == 0 - assert result.output == "bar\nfoo\n" +def test_unconfigured( + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + other_repo = tmp_path / "some-other-repo" + other_repo.mkdir() + os.chdir(tmp_path) -def test_unconfigured(runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - Path("some-repo").mkdir() - Path("some-other-repo").mkdir() - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-repo """ - ) + ) + + config = get_config() + config.read("repo-man.cfg") - config = get_config() - config.read("repo-man.cfg") + result = runner.invoke(cli, ["sniff", "--unconfigured"], obj=config) + assert result.exit_code == 0 + assert result.output == "some-other-repo\n" - result = runner.invoke(cli, ["sniff", "--unconfigured"], obj=config) - assert result.exit_code == 0 - assert result.output == "some-other-repo\n" +def test_duplicates( + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + other_repo = tmp_path / "some-other-repo" + other_repo.mkdir() + os.chdir(tmp_path) -def test_duplicates(runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-repo some-other-repo @@ -71,11 +87,11 @@ def test_duplicates(runner: testing.CliRunner, get_config: Callable[[], configpa yet-another-repo """ - ) + ) - config = get_config() - config.read("repo-man.cfg") + config = get_config() + config.read("repo-man.cfg") - result = runner.invoke(cli, ["sniff", "--duplicates"], obj=config) - assert result.exit_code == 0 - assert result.output == "some-other-repo\nsome-repo\n" + result = runner.invoke(cli, ["sniff", "--duplicates"], obj=config) + assert result.exit_code == 0 + assert result.output == "some-other-repo\nsome-repo\n" diff --git a/test/test_types.py b/test/test_types.py index 0f91c4b..f9d1d3a 100644 --- a/test/test_types.py +++ b/test/test_types.py @@ -1,4 +1,5 @@ import configparser +import os from collections.abc import Callable from pathlib import Path @@ -7,22 +8,28 @@ from repo_man.cli import cli -def test_types_clean(runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - Path("some-repo").mkdir() - config = get_config() - result = runner.invoke(cli, ["types", "some-repo"], obj=config) - assert result.exit_code == 1 - assert result.output == "No repo-man.cfg file found.\n" +def test_types_clean( + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) + config = get_config() + result = runner.invoke(cli, ["types", "some-repo"], obj=config) + assert result.exit_code == 1 + assert result.output == "No repo-man.cfg file found.\n" -def test_types_when_configured(runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - Path("some-repo").mkdir() +def test_types_when_configured( + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-repo @@ -31,49 +38,53 @@ def test_types_when_configured(runner: testing.CliRunner, get_config: Callable[[ some-other-repo """ - ) + ) - config = get_config() - result = runner.invoke(cli, ["types", "some-repo"], obj=config) - assert result.exit_code == 0 - assert result.output == "foo\n" + config = get_config() + result = runner.invoke(cli, ["types", "some-repo"], obj=config) + assert result.exit_code == 0 + assert result.output == "foo\n" def test_types_when_not_configured( - runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser] + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path ) -> None: - with runner.isolated_filesystem(): - Path("some-repo").mkdir() + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-other-repo """ - ) + ) - config = get_config() - result = runner.invoke(cli, ["types", "some-repo"], obj=config) - assert result.exit_code == 0 - assert result.output == "" + config = get_config() + result = runner.invoke(cli, ["types", "some-repo"], obj=config) + assert result.exit_code == 0 + assert result.output == "" -def test_types_when_ignored(runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser]) -> None: - with runner.isolated_filesystem(): - Path("some-repo").mkdir() +def test_types_when_ignored( + runner: testing.CliRunner, get_config: Callable[[], configparser.ConfigParser], tmp_path: Path +) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[ignore] + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[ignore] known = some-repo """ - ) + ) - config = get_config() - result = runner.invoke(cli, ["types", "some-repo"], obj=config) - assert result.exit_code == 0 - assert result.output == "" + config = get_config() + result = runner.invoke(cli, ["types", "some-repo"], obj=config) + assert result.exit_code == 0 + assert result.output == "" diff --git a/test/test_utils.py b/test/test_utils.py index 8ed285c..698e38a 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -1,16 +1,22 @@ +import os +from pathlib import Path + from typer import testing from repo_man.utils import get_valid_repo_types -def test_get_valid_repo_types(runner: testing.CliRunner) -> None: - with runner.isolated_filesystem(): - with open("repo-man.cfg", "w") as config_file: - config_file.write( - """[foo] +def test_get_valid_repo_types(runner: testing.CliRunner, tmp_path: Path) -> None: + repo = tmp_path / "some-repo" + repo.mkdir() + os.chdir(tmp_path) + + with open("repo-man.cfg", "w") as config_file: + config_file.write( + """[foo] known = some-repo """ - ) + ) - assert get_valid_repo_types() == ["all", "foo"] + assert get_valid_repo_types() == ["all", "foo"] From 825c72849e23648370a2810af4f8bb58f7e57ecb Mon Sep 17 00:00:00 2001 From: Dane Hillard Date: Mon, 22 Jun 2026 09:36:00 -0400 Subject: [PATCH 2/2] Update Ubuntu version for docs build --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index c64b170..c0a8562 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -7,7 +7,7 @@ formats: - htmlzip build: - os: ubuntu-20.04 + os: ubuntu-26.04 tools: python: "3.14"