From 05aec2e814114a8a54845f3731e09b701ea6657e Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 8 Jun 2024 07:26:58 -0500 Subject: [PATCH 1/7] tests(cli): Use `NamedTuple` for fixtures --- tests/test_cli.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/test_cli.py b/tests/test_cli.py index 97f2b7f..483e6ef 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -27,8 +27,41 @@ def get_output( (["g", "--help"], "git --help"), ], ) +class CommandLineTestFixture(t.NamedTuple): + """Test fixture for CLI params, environment, and expected result.""" + + # pytest internal + test_id: str + + # test data + argv_args: t.List[str] + + # results + expect_cmd: str + + +TEST_FIXTURES: t.List[CommandLineTestFixture] = [ + CommandLineTestFixture( + test_id="g-cmd-inside-git-dir", + argv_args=["g"], + expect_cmd="git", + ), + CommandLineTestFixture( + test_id="g-cmd-help-inside-git-dir", + argv_args=["g --help"], + expect_cmd="git --help", + ), +] + + +@pytest.mark.parametrize( + list(CommandLineTestFixture._fields), + TEST_FIXTURES, + ids=[f.test_id for f in TEST_FIXTURES], +) def test_command_line( # capsys: pytest.CaptureFixture[str], + test_id: str, argv_args: t.List[str], expect_cmd: str, ) -> None: From 3e5ce5a356dccd1c724e1d8cba13b6bd9995596e Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 8 Jun 2024 07:31:46 -0500 Subject: [PATCH 2/7] tests(cli): Add `EnvFlag` --- tests/test_cli.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/test_cli.py b/tests/test_cli.py index 483e6ef..eb22931 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,5 +1,7 @@ """Tests for g's CLI package.""" +import enum +import pathlib import subprocess import typing as t from unittest.mock import patch @@ -20,6 +22,13 @@ def get_output( return exc.output +class EnvFlag(enum.Enum): + """Environmental conditions to simulate in test case.""" + + Git = "Git" # Inside a git directory (like this repo) + Empty = "Empty" # Empty directory (e.g. `tmp_path`) + + @pytest.mark.parametrize( ("argv_args", "expect_cmd"), [ @@ -33,6 +42,9 @@ class CommandLineTestFixture(t.NamedTuple): # pytest internal test_id: str + # env data + env: EnvFlag + # test data argv_args: t.List[str] @@ -43,11 +55,13 @@ class CommandLineTestFixture(t.NamedTuple): TEST_FIXTURES: t.List[CommandLineTestFixture] = [ CommandLineTestFixture( test_id="g-cmd-inside-git-dir", + env=EnvFlag.Git, argv_args=["g"], expect_cmd="git", ), CommandLineTestFixture( test_id="g-cmd-help-inside-git-dir", + env=EnvFlag.Git, argv_args=["g --help"], expect_cmd="git --help", ), @@ -62,12 +76,20 @@ class CommandLineTestFixture(t.NamedTuple): def test_command_line( # capsys: pytest.CaptureFixture[str], test_id: str, + env: EnvFlag, argv_args: t.List[str], expect_cmd: str, + monkeypatch: pytest.MonkeyPatch, + tmp_path: pathlib.Path, ) -> None: """Basic CLI usage.""" from g import sys as gsys + if env == EnvFlag.Git: + pass + elif env == EnvFlag.Empty: + monkeypatch.chdir(str(tmp_path)) + with patch.object(gsys, "argv", argv_args): proc = run(wait=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) assert proc is not None From 605bb4a6c013715728b06dcaa1fa42e4029739a4 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 8 Jun 2024 07:32:51 -0500 Subject: [PATCH 3/7] tests(cli): Recreate `AssertionError` --- tests/test_cli.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_cli.py b/tests/test_cli.py index eb22931..6c9bfe7 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -65,6 +65,18 @@ class CommandLineTestFixture(t.NamedTuple): argv_args=["g --help"], expect_cmd="git --help", ), + CommandLineTestFixture( + test_id="g-cmd-inside-empty-dir", + env=EnvFlag.Empty, + argv_args=["g"], + expect_cmd="git", + ), + CommandLineTestFixture( + test_id="g-cmd-help-inside-empty-dir", + env=EnvFlag.Empty, + argv_args=["g --help"], + expect_cmd="git --help", + ), ] From da2e087180647f1411b86c5dcd917bdbdfa114c1 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 8 Jun 2024 07:58:04 -0500 Subject: [PATCH 4/7] g: Handle cases where not in a VCS directory --- src/g/__init__.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/g/__init__.py b/src/g/__init__.py index 0091582..059f872 100755 --- a/src/g/__init__.py +++ b/src/g/__init__.py @@ -1,6 +1,8 @@ #!/usr/bin/env python """Package for g.""" +import io +import logging import os import pathlib import subprocess @@ -12,6 +14,8 @@ vcspath_registry = {".git": "git", ".svn": "svn", ".hg": "hg"} +log = logging.getLogger(__name__) + def find_repo_type(path: t.Union[pathlib.Path, str]) -> t.Optional[str]: for _path in [*list(pathlib.Path(path).parents), pathlib.Path(path)]: @@ -45,6 +49,13 @@ def run( if cmd_args is DEFAULT: cmd_args = sys.argv[1:] + logging.basicConfig(level=logging.INFO, format="%(message)s") + + if cmd is None: + msg = "No VCS found in current directory." + log.info(msg) + return None + assert isinstance(cmd_args, (tuple, list)) assert isinstance(cmd, (str, bytes, pathlib.Path)) From bc2edcf6828aa124814846db5705cd8a972c8d7a Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 8 Jun 2024 07:59:31 -0500 Subject: [PATCH 5/7] docs(find_repo_type): Add docstring --- src/g/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g/__init__.py b/src/g/__init__.py index 059f872..7386812 100755 --- a/src/g/__init__.py +++ b/src/g/__init__.py @@ -18,6 +18,7 @@ def find_repo_type(path: t.Union[pathlib.Path, str]) -> t.Optional[str]: + """Detect repo type looking upwards.""" for _path in [*list(pathlib.Path(path).parents), pathlib.Path(path)]: for p in _path.iterdir(): if p.is_dir() and p.name in vcspath_registry: From d697a7bfe39ec306b51cf0958e5704540e64b799 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 8 Jun 2024 07:59:55 -0500 Subject: [PATCH 6/7] tests(test_command_line): Test behavior when outside VCS directory --- tests/test_cli.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 6c9bfe7..262f15a 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -49,7 +49,7 @@ class CommandLineTestFixture(t.NamedTuple): argv_args: t.List[str] # results - expect_cmd: str + expect_cmd: t.Optional[str] TEST_FIXTURES: t.List[CommandLineTestFixture] = [ @@ -69,13 +69,13 @@ class CommandLineTestFixture(t.NamedTuple): test_id="g-cmd-inside-empty-dir", env=EnvFlag.Empty, argv_args=["g"], - expect_cmd="git", + expect_cmd=None, ), CommandLineTestFixture( test_id="g-cmd-help-inside-empty-dir", env=EnvFlag.Empty, argv_args=["g --help"], - expect_cmd="git --help", + expect_cmd=None, ), ] @@ -90,7 +90,7 @@ def test_command_line( test_id: str, env: EnvFlag, argv_args: t.List[str], - expect_cmd: str, + expect_cmd: t.Optional[str], monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path, ) -> None: @@ -104,8 +104,13 @@ def test_command_line( with patch.object(gsys, "argv", argv_args): proc = run(wait=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - assert proc is not None - assert proc.stdout is not None - captured = proc.stdout.read() - - assert captured == get_output(expect_cmd, shell=True, stderr=subprocess.STDOUT) + if expect_cmd is None: + assert proc is None + else: + assert proc is not None + assert proc.stdout is not None + captured = proc.stdout.read() + + assert captured == get_output( + expect_cmd, shell=True, stderr=subprocess.STDOUT + ) From c0d2041465d4619bbff21dbc4405e6be299d1c15 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 8 Jun 2024 08:00:36 -0500 Subject: [PATCH 7/7] docs(CHANGES): Fix `g` when running outside of vcs --- CHANGES | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGES b/CHANGES index 7e72123..bfd51c8 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,15 @@ $ pipx install --suffix=@next g --pip-args '\--pre' --force +### Fixes + +- Fix `g` when running outside of a VCS directory (#24) + +### Tests + +- Use declarative, typed `NamedTuple`-style for `test_command_line` fixtures + (#24) + ### Development - poetry: 1.8.1 -> 1.8.2 @@ -49,14 +58,17 @@ _Maintenance only, no bug fixes, or new features_ --exec 'poetry run ruff check --select ALL . --fix --unsafe-fixes --preview --show-fixes; poetry run ruff format .; git add src tests; git commit --amend --no-edit' \ origin/master ``` + - poetry: 1.7.1 -> 1.8.1 See also: https://github.com/python-poetry/poetry/blob/1.8.1/CHANGELOG.md + - ruff 0.2.2 -> 0.3.0 (#22) Related formattings. Update CI to use `ruff check .` instead of `ruff .`. See also: https://github.com/astral-sh/ruff/blob/v0.3.0/CHANGELOG.md + - Strengthen linting (#21) - Add flake8-commas (COM)