summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonny Pfannschmidt <opensource@ronnypfannschmidt.de>2023-02-25 21:49:56 +0100
committerRonny Pfannschmidt <opensource@ronnypfannschmidt.de>2023-03-11 22:06:31 +0100
commit7d851ecb653d0d8cac3aa332b7a43b6e786d4c79 (patch)
treef7989cc06ce1ab0f82c59d86631e06e427b9ab8b
parentdb92fbde296782bee7b32c2afc8b9afbb4d24c4a (diff)
downloadsetuptools-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.in2
-rw-r--r--src/setuptools_scm/_run_cmd.py3
-rw-r--r--src/setuptools_scm/_trace.py14
-rw-r--r--src/setuptools_scm/_types.py3
-rw-r--r--src/setuptools_scm/file_finder_git.py13
-rw-r--r--src/setuptools_scm/file_finder_hg.py8
-rw-r--r--src/setuptools_scm/utils.py5
-rw-r--r--testing/conftest.py5
-rw-r--r--testing/test_basic_api.py13
-rw-r--r--testing/test_regressions.py25
-rw-r--r--tox.ini8
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
diff --git a/tox.ini b/tox.ini
index 581f62c..b183b09 100644
--- a/tox.ini
+++ b/tox.ini
@@ -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 []