diff options
author | Ronny Pfannschmidt <opensource@ronnypfannschmidt.de> | 2023-02-25 21:49:56 +0100 |
---|---|---|
committer | Ronny Pfannschmidt <opensource@ronnypfannschmidt.de> | 2023-03-11 22:06:31 +0100 |
commit | 7d851ecb653d0d8cac3aa332b7a43b6e786d4c79 (patch) | |
tree | f7989cc06ce1ab0f82c59d86631e06e427b9ab8b | |
parent | db92fbde296782bee7b32c2afc8b9afbb4d24c4a (diff) | |
download | setuptools-scm-7d851ecb653d0d8cac3aa332b7a43b6e786d4c79.tar.gz |
refactor: unify command running apis
introduces the _run_cmd private module
which is used across the board
starts to remove use of the do/do_ex which predate
-rw-r--r-- | MANIFEST.in | 2 | ||||
-rw-r--r-- | src/setuptools_scm/_run_cmd.py | 3 | ||||
-rw-r--r-- | src/setuptools_scm/_trace.py | 14 | ||||
-rw-r--r-- | src/setuptools_scm/_types.py | 3 | ||||
-rw-r--r-- | src/setuptools_scm/file_finder_git.py | 13 | ||||
-rw-r--r-- | src/setuptools_scm/file_finder_hg.py | 8 | ||||
-rw-r--r-- | src/setuptools_scm/utils.py | 5 | ||||
-rw-r--r-- | testing/conftest.py | 5 | ||||
-rw-r--r-- | testing/test_basic_api.py | 13 | ||||
-rw-r--r-- | testing/test_regressions.py | 25 | ||||
-rw-r--r-- | tox.ini | 8 |
11 files changed, 50 insertions, 49 deletions
diff --git a/MANIFEST.in b/MANIFEST.in index 11d563c..fc1b532 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -11,4 +11,4 @@ include mypy.ini include testing/Dockerfile.* include src/setuptools_scm/.git_archival.txt recursive-include testing *.bash -exclude nextgen +prune nextgen diff --git a/src/setuptools_scm/_run_cmd.py b/src/setuptools_scm/_run_cmd.py index 83b0b19..14fda9c 100644 --- a/src/setuptools_scm/_run_cmd.py +++ b/src/setuptools_scm/_run_cmd.py @@ -61,8 +61,10 @@ def ensure_stripped_str(str_or_bytes: str | bytes) -> str: def run( cmd: _t.CMD_TYPE, cwd: _t.PathT, + *, strip: bool = True, trace: bool = True, + timeout: int = 20, ) -> subprocess.CompletedProcess[str]: if isinstance(cmd, str): cmd = shlex.split(cmd) @@ -81,6 +83,7 @@ def run( HGPLAIN="1", ), text=True, + timeout=timeout, ) if strip: if res.stdout: diff --git a/src/setuptools_scm/_trace.py b/src/setuptools_scm/_trace.py index 01383a5..cf5fcfa 100644 --- a/src/setuptools_scm/_trace.py +++ b/src/setuptools_scm/_trace.py @@ -3,6 +3,7 @@ from __future__ import annotations import os import sys import textwrap +from typing import Sequence from . import _types as _t @@ -16,11 +17,14 @@ def trace(*k: object, indent: bool = False) -> None: print(*k, file=sys.stderr, flush=True) -def trace_command(cmd: _t.CMD_TYPE, cwd: _t.PathT) -> None: +def _unsafe_quote_for_display(item: _t.PathT) -> str: + # give better results than shlex.join in our cases + text = os.fspath(item) + return text if all(c not in text for c in " {[:") else f'"{text}"' + + +def trace_command(cmd: Sequence[_t.PathT], cwd: _t.PathT) -> None: if not DEBUG: return - # give better results than shlex.join in our cases - cmd_4_trace = " ".join( - [s if all(c not in s for c in " {[:") else f'"{s}"' for s in cmd] - ) + cmd_4_trace = " ".join(map(_unsafe_quote_for_display, cmd)) trace(f"---\n > {cwd}\\$ ", cmd_4_trace, indent=True) diff --git a/src/setuptools_scm/_types.py b/src/setuptools_scm/_types.py index 5c2cd33..7cd57a1 100644 --- a/src/setuptools_scm/_types.py +++ b/src/setuptools_scm/_types.py @@ -4,6 +4,7 @@ import os from typing import Any from typing import Callable from typing import List +from typing import Sequence from typing import Tuple from typing import TypeVar from typing import Union @@ -16,7 +17,7 @@ from . import version PathT: TypeAlias = Union["os.PathLike[str]", str] -CMD_TYPE: TypeAlias = Union[List[str], str] +CMD_TYPE: TypeAlias = Union[Sequence[PathT], str] VERSION_SCHEME: TypeAlias = Union[str, Callable[["version.ScmVersion"], str]] VERSION_SCHEMES: TypeAlias = Union[List[str], Tuple[str, ...], VERSION_SCHEME] diff --git a/src/setuptools_scm/file_finder_git.py b/src/setuptools_scm/file_finder_git.py index c16cff6..20c04a1 100644 --- a/src/setuptools_scm/file_finder_git.py +++ b/src/setuptools_scm/file_finder_git.py @@ -7,11 +7,11 @@ import tarfile from typing import IO from . import _types as _t +from ._run_cmd import run as _run from ._trace import trace from .file_finder import is_toplevel_acceptable from .file_finder import scm_find_files from .utils import data_from_mime -from .utils import do_ex log = logging.getLogger(__name__) @@ -19,18 +19,18 @@ log = logging.getLogger(__name__) def _git_toplevel(path: str) -> str | None: try: cwd = os.path.abspath(path or ".") - out, err, ret = do_ex(["git", "rev-parse", "HEAD"], cwd=cwd) - if ret != 0: + res = _run(["git", "rev-parse", "HEAD"], cwd=cwd) + if res.returncode: # BAIL if there is no commit log.error("listing git files failed - pretending there aren't any") return None - out, err, ret = do_ex( + res = _run( ["git", "rev-parse", "--show-prefix"], cwd=cwd, ) - if ret != 0: + if res.returncode: return None - out = out.strip()[:-1] # remove the trailing pathsep + out = res.stdout[:-1] # remove the trailing pathsep if not out: out = cwd else: @@ -92,7 +92,6 @@ def git_find_files(path: _t.PathT = "") -> list[str]: toplevel = _git_toplevel(os.fspath(path)) if not is_toplevel_acceptable(toplevel): return [] - assert toplevel is not None # mypy ignores typeguard fullpath = os.path.abspath(os.path.normpath(path)) if not fullpath.startswith(toplevel): trace("toplevel mismatch", toplevel, fullpath) diff --git a/src/setuptools_scm/file_finder_hg.py b/src/setuptools_scm/file_finder_hg.py index 30f28b9..a02bcce 100644 --- a/src/setuptools_scm/file_finder_hg.py +++ b/src/setuptools_scm/file_finder_hg.py @@ -4,6 +4,7 @@ import os import subprocess from . import _types as _t +from ._run_cmd import run as _run from ._trace import trace from .file_finder import is_toplevel_acceptable from .file_finder import scm_find_files @@ -13,13 +14,12 @@ from .utils import do_ex def _hg_toplevel(path: str) -> str | None: try: - out: str = subprocess.check_output( + res = _run( ["hg", "root"], cwd=(path or "."), - text=True, - stderr=subprocess.DEVNULL, ) - return os.path.normcase(os.path.realpath(out.strip())) + res.check_returncode() + return os.path.normcase(os.path.realpath(res.stdout)) except subprocess.CalledProcessError: # hg returned error, we are not in a mercurial repo return None diff --git a/src/setuptools_scm/utils.py b/src/setuptools_scm/utils.py index d7d661c..09d8af7 100644 --- a/src/setuptools_scm/utils.py +++ b/src/setuptools_scm/utils.py @@ -25,11 +25,10 @@ class _CmdResult(NamedTuple): def do_ex(cmd: _t.CMD_TYPE, cwd: _t.PathT = ".") -> _CmdResult: res = _run_cmd.run(cmd, cwd) - return _CmdResult(res.stdout, res.stderr, res.returncode) -def do(cmd: list[str] | str, cwd: str | _t.PathT = ".") -> str: +def do(cmd: _t.CMD_TYPE, cwd: _t.PathT = ".") -> str: out, err, ret = do_ex(cmd, cwd) if ret and not _trace.DEBUG: print(err) @@ -68,4 +67,4 @@ def has_command(name: str, args: list[str] | None = None, warn: bool = True) -> def require_command(name: str) -> None: if not has_command(name, warn=False): - raise OSError("%r was not found" % name) + raise OSError(f"{name!r} was not found") diff --git a/testing/conftest.py b/testing/conftest.py index b0a4b0e..e1c8160 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -8,6 +8,7 @@ import pytest import setuptools_scm.utils from .wd_wrapper import WorkDir +from setuptools_scm._run_cmd import run def pytest_configure() -> None: @@ -69,8 +70,6 @@ def wd(tmp_path: Path) -> WorkDir: @pytest.fixture def repositories_hg_git(tmp_path: Path) -> tuple[WorkDir, WorkDir]: - from setuptools_scm.utils import do - tmp_path = tmp_path.resolve() path_git = tmp_path / "repo_git" path_git.mkdir() @@ -83,7 +82,7 @@ def repositories_hg_git(tmp_path: Path) -> tuple[WorkDir, WorkDir]: wd.commit_command = "git commit -m test-{reason}" path_hg = tmp_path / "repo_hg" - do(f"hg clone {path_git} {path_hg} --config extensions.hggit=") + run(["hg", "clone", path_git, path_hg, "--config", "extensions.hggit="], tmp_path) assert path_hg.exists() with open(path_hg / ".hg/hgrc", "a") as file: diff --git a/testing/test_basic_api.py b/testing/test_basic_api.py index 4bd72fa..1aef0bd 100644 --- a/testing/test_basic_api.py +++ b/testing/test_basic_api.py @@ -10,6 +10,7 @@ import pytest import setuptools_scm from setuptools_scm import Configuration from setuptools_scm import dump_version +from setuptools_scm._run_cmd import run from setuptools_scm.utils import data_from_mime from setuptools_scm.utils import do from setuptools_scm.version import ScmVersion @@ -76,8 +77,8 @@ def test_parentdir_prefix(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> No setup(use_scm_version={"parentdir_prefix_version": "projectname-"}) """ ) - res = do([sys.executable, "setup.py", "--version"], p) - assert res == "12.34" + res = run([sys.executable, "setup.py", "--version"], p) + assert res.stdout == "12.34" def test_fallback(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: @@ -103,8 +104,8 @@ def test_empty_pretend_version(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) setup(use_scm_version={"fallback_version": "12.34"}) """ ) - res = do([sys.executable, "setup.py", "--version"], p) - assert res == "12.34" + res = run([sys.executable, "setup.py", "--version"], p) + assert res.stdout == "12.34" def test_empty_pretend_version_named( @@ -121,8 +122,8 @@ def test_empty_pretend_version_named( setup(name="myscm", use_scm_version={"fallback_version": "12.34"}) """ ) - res = do([sys.executable, "setup.py", "--version"], p) - assert res == "12.34" + res = run([sys.executable, "setup.py", "--version"], p) + assert res.stdout == "12.34" @pytest.mark.parametrize( diff --git a/testing/test_regressions.py b/testing/test_regressions.py index 6cbabcc..f7b4b17 100644 --- a/testing/test_regressions.py +++ b/testing/test_regressions.py @@ -18,8 +18,7 @@ import pytest from setuptools_scm import Configuration from setuptools_scm import get_version from setuptools_scm.git import parse -from setuptools_scm.utils import do -from setuptools_scm.utils import do_ex +from setuptools_scm._run_cmd import run def test_pkginfo_noscmroot(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: @@ -35,21 +34,21 @@ def test_pkginfo_noscmroot(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> N "from setuptools import setup;" 'setup(use_scm_version={"root": ".."})' ) - _, stderr, ret = do_ex([sys.executable, "setup.py", "--version"], p) - assert "setuptools-scm was unable to detect version for" in stderr - assert ret == 1 + res = run([sys.executable, "setup.py", "--version"], p) + assert "setuptools-scm was unable to detect version for" in res.stderr + assert res.returncode == 1 p.joinpath("PKG-INFO").write_text("Version: 1.0") - res = do([sys.executable, "setup.py", "--version"], p) - assert res == "1.0" + res = run([sys.executable, "setup.py", "--version"], p) + assert res.stdout == "1.0" try: - do("git init", p.parent) + run("git init", p.parent) except OSError: pass else: - res = do([sys.executable, "setup.py", "--version"], p) - assert res == "0.1.dev0" + res = run([sys.executable, "setup.py", "--version"], p) + assert res.stdout == "0.1.dev0" def test_pip_egg_info(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: @@ -99,8 +98,8 @@ setup(use_scm_version=vcfg) ) p.joinpath("PKG-INFO").write_text("Version: 1.0") - res = do([sys.executable, "setup.py", "--version"], p) - assert res == "1.0" + res = run([sys.executable, "setup.py", "--version"], p) + assert res.stdout == "1.0" @pytest.mark.skipif(sys.platform != "win32", reason="this bug is only valid on windows") @@ -108,7 +107,7 @@ def test_case_mismatch_on_windows_git(tmp_path: Path) -> None: """Case insensitive path checks on Windows""" camel_case_path = tmp_path / "CapitalizedDir" camel_case_path.mkdir() - do("git init", camel_case_path) + run("git init", camel_case_path) res = parse(str(camel_case_path).lower(), Configuration()) assert res is not None @@ -1,5 +1,5 @@ [tox] -envlist=py{37,38,39,310,311}-{test,selfcheck},check_readme,check-dist +envlist=py{37,38,39,310,311},check_readme,check-dist [pytest] testpaths=testing @@ -21,17 +21,13 @@ ignore=E203,W503 [testenv] usedevelop=True -skip_install= - selfcheck: True - test: False deps= pytest setuptools >= 45 virtualenv>20 typing_extensions commands= - test: pytest [] - selfcheck: python setup.py --version + pytest [] |