diff options
author | Ronny Pfannschmidt <opensource@ronnypfannschmidt.de> | 2023-03-11 22:43:44 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-11 22:43:44 +0100 |
commit | 792f61e3ab701cd851d2071885106df581343e0e (patch) | |
tree | 03ab91ee3c63e0f5b892dd11f87fc351faa20c2e | |
parent | 6d1d966411d5ca98186dd2fb7e22751e1f034dc1 (diff) | |
parent | 97ef8752f5d6ae5dd3f4e7997ce6c98caa4e22fb (diff) | |
download | setuptools-scm-792f61e3ab701cd851d2071885106df581343e0e.tar.gz |
Merge pull request #808 from RonnyPfannschmidt/ronny/cmd-refactor
refactor: split tracing and command running into own modules
27 files changed, 229 insertions, 214 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c32c140..15273bf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,7 +34,7 @@ repos: - id: pyproject-fmt - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.0.0' + rev: 'v1.0.1' hooks: - id: mypy args: [--strict] @@ -44,3 +44,4 @@ repos: - tokenize-rt==3.2.0 - pytest == 7.1 - importlib_metadata + - typing-extensions>=4.5 diff --git a/MANIFEST.in b/MANIFEST.in index 54e9473..fc1b532 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -11,3 +11,4 @@ include mypy.ini include testing/Dockerfile.* include src/setuptools_scm/.git_archival.txt recursive-include testing *.bash +prune nextgen diff --git a/src/setuptools_scm/__init__.py b/src/setuptools_scm/__init__.py index d6def65..eccc68f 100644 --- a/src/setuptools_scm/__init__.py +++ b/src/setuptools_scm/__init__.py @@ -49,7 +49,7 @@ def dump_version( target = os.path.normpath(os.path.join(root, write_to)) ext = os.path.splitext(target)[1] template = template or TEMPLATES.get(ext) - from .utils import trace + from ._trace import trace trace("dump", write_to, version) if template is None: @@ -106,7 +106,7 @@ def _version_missing(config: Configuration) -> NoReturn: def get_version( - root: str = ".", + root: _t.PathT = ".", version_scheme: _t.VERSION_SCHEME = DEFAULT_VERSION_SCHEME, local_scheme: _t.VERSION_SCHEME = DEFAULT_LOCAL_SCHEME, write_to: _t.PathT | None = None, diff --git a/src/setuptools_scm/_config.py b/src/setuptools_scm/_config.py index 84f7227..34745ae 100644 --- a/src/setuptools_scm/_config.py +++ b/src/setuptools_scm/_config.py @@ -15,10 +15,10 @@ from ._integration.pyproject_reading import ( ) from ._integration.pyproject_reading import read_pyproject as _read_pyproject from ._overrides import read_toml_overrides +from ._trace import trace from ._version_cls import _validate_version_cls from ._version_cls import _VersionT from ._version_cls import Version as _Version -from .utils import trace DEFAULT_TAG_REGEX = re.compile( r"^(?:[\w-]+-)?(?P<version>[vV]?\d+(?:\.\d+){0,2}[^\+]*)(?:\+.*)?$" diff --git a/src/setuptools_scm/_entrypoints.py b/src/setuptools_scm/_entrypoints.py index 0b0b32c..9b5b093 100644 --- a/src/setuptools_scm/_entrypoints.py +++ b/src/setuptools_scm/_entrypoints.py @@ -9,7 +9,7 @@ from typing import overload from typing import TYPE_CHECKING from . import version -from .utils import trace +from ._trace import trace if TYPE_CHECKING: from ._config import Configuration diff --git a/src/setuptools_scm/_overrides.py b/src/setuptools_scm/_overrides.py index 9040487..f08f170 100644 --- a/src/setuptools_scm/_overrides.py +++ b/src/setuptools_scm/_overrides.py @@ -6,7 +6,7 @@ from typing import Any from . import _config from . import version from ._integration.pyproject_reading import lazy_toml_load -from .utils import trace +from ._trace import trace PRETEND_KEY = "SETUPTOOLS_SCM_PRETEND_VERSION" PRETEND_KEY_NAMED = PRETEND_KEY + "_FOR_{name}" diff --git a/src/setuptools_scm/_run_cmd.py b/src/setuptools_scm/_run_cmd.py new file mode 100644 index 0000000..b528504 --- /dev/null +++ b/src/setuptools_scm/_run_cmd.py @@ -0,0 +1,104 @@ +from __future__ import annotations + +import os +import shlex +import subprocess +from typing import Mapping + +from . import _trace +from . import _types as _t + + +def no_git_env(env: Mapping[str, str]) -> dict[str, str]: + # adapted from pre-commit + # Too many bugs dealing with environment variables and GIT: + # https://github.com/pre-commit/pre-commit/issues/300 + # In git 2.6.3 (maybe others), git exports GIT_WORK_TREE while running + # pre-commit hooks + # In git 1.9.1 (maybe others), git exports GIT_DIR and GIT_INDEX_FILE + # while running pre-commit hooks in submodules. + # GIT_DIR: Causes git clone to clone wrong thing + # GIT_INDEX_FILE: Causes 'error invalid object ...' during commit + for k, v in env.items(): + if k.startswith("GIT_"): + _trace.trace(k, v) + return { + k: v + for k, v in env.items() + if not k.startswith("GIT_") + or k in ("GIT_EXEC_PATH", "GIT_SSH", "GIT_SSH_COMMAND") + } + + +def avoid_pip_isolation(env: Mapping[str, str]) -> dict[str, str]: + """ + pip build isolation can break Mercurial + (see https://github.com/pypa/pip/issues/10635) + + pip uses PYTHONNOUSERSITE and a path in PYTHONPATH containing "pip-build-env-". + """ + new_env = {k: v for k, v in env.items() if k != "PYTHONNOUSERSITE"} + if "PYTHONPATH" not in new_env: + return new_env + + new_env["PYTHONPATH"] = os.pathsep.join( + [ + path + for path in new_env["PYTHONPATH"].split(os.pathsep) + if "pip-build-env-" not in path + ] + ) + return new_env + + +def ensure_stripped_str(str_or_bytes: str | bytes) -> str: + if isinstance(str_or_bytes, str): + return str_or_bytes.strip() + else: + return str_or_bytes.decode("utf-8", "surrogateescape").strip() + + +def run( + cmd: _t.CMD_TYPE, + cwd: _t.PathT, + *, + strip: bool = True, + trace: bool = True, + timeout: int = 20, + check: bool = False, +) -> subprocess.CompletedProcess[str]: + if isinstance(cmd, str): + cmd = shlex.split(cmd) + else: + cmd = [os.fspath(x) for x in cmd] + if trace: + _trace.trace_command(cmd, cwd) + res = subprocess.run( + cmd, + capture_output=True, + cwd=str(cwd), + env=dict( + avoid_pip_isolation(no_git_env(os.environ)), + # os.environ, + # try to disable i18n + LC_ALL="C", + LANGUAGE="", + HGPLAIN="1", + ), + text=True, + timeout=timeout, + ) + if strip: + if res.stdout: + res.stdout = ensure_stripped_str(res.stdout) + res.stderr = ensure_stripped_str(res.stderr) + if trace: + if res.stdout: + _trace.trace("out:\n", res.stdout, indent=True) + if res.stderr: + _trace.trace("err:\n", res.stderr, indent=True) + if res.returncode: + _trace.trace("ret:", res.returncode) + if check: + res.check_returncode() + return res diff --git a/src/setuptools_scm/_trace.py b/src/setuptools_scm/_trace.py new file mode 100644 index 0000000..cf5fcfa --- /dev/null +++ b/src/setuptools_scm/_trace.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +import os +import sys +import textwrap +from typing import Sequence + +from . import _types as _t + +DEBUG: bool = bool(os.environ.get("SETUPTOOLS_SCM_DEBUG")) + + +def trace(*k: object, indent: bool = False) -> None: + if not DEBUG: + if indent and len(k) > 1: + k = (k[0],) + tuple(textwrap.indent(str(s), " ") for s in k[1:]) + print(*k, file=sys.stderr, flush=True) + + +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 + 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/discover.py b/src/setuptools_scm/discover.py index 58384aa..2bd01e9 100644 --- a/src/setuptools_scm/discover.py +++ b/src/setuptools_scm/discover.py @@ -6,7 +6,7 @@ from typing import Iterator from . import _types as _t from ._config import Configuration -from .utils import trace +from ._trace import trace def walk_potential_roots( diff --git a/src/setuptools_scm/file_finder.py b/src/setuptools_scm/file_finder.py index 27196c0..27a50d7 100644 --- a/src/setuptools_scm/file_finder.py +++ b/src/setuptools_scm/file_finder.py @@ -5,7 +5,7 @@ import os from typing_extensions import TypeGuard from . import _types as _t -from .utils import trace +from ._trace import trace def scm_find_files( diff --git a/src/setuptools_scm/file_finder_git.py b/src/setuptools_scm/file_finder_git.py index 65aa999..20c04a1 100644 --- a/src/setuptools_scm/file_finder_git.py +++ b/src/setuptools_scm/file_finder_git.py @@ -7,12 +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 -from .utils import trace - log = logging.getLogger(__name__) @@ -20,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: @@ -93,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 b750fea..a02bcce 100644 --- a/src/setuptools_scm/file_finder_hg.py +++ b/src/setuptools_scm/file_finder_hg.py @@ -4,22 +4,22 @@ 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 from .utils import data_from_mime from .utils import do_ex -from .utils import trace 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/git.py b/src/setuptools_scm/git.py index 1859671..484bd4d 100644 --- a/src/setuptools_scm/git.py +++ b/src/setuptools_scm/git.py @@ -13,12 +13,12 @@ from typing import TYPE_CHECKING from . import _types as _t from . import Configuration +from ._trace import trace from .scm_workdir import Workdir from .utils import _CmdResult from .utils import data_from_mime from .utils import do_ex from .utils import require_command -from .utils import trace from .version import meta from .version import ScmVersion from .version import tag_to_version diff --git a/src/setuptools_scm/hacks.py b/src/setuptools_scm/hacks.py index 1ddcdfa..5aaa0db 100644 --- a/src/setuptools_scm/hacks.py +++ b/src/setuptools_scm/hacks.py @@ -7,7 +7,7 @@ if TYPE_CHECKING: from . import _types as _t from . import Configuration from .utils import data_from_mime -from .utils import trace +from ._trace import trace from .version import meta from .version import ScmVersion from .version import tag_to_version diff --git a/src/setuptools_scm/hg.py b/src/setuptools_scm/hg.py index a6f5725..e7295bc 100644 --- a/src/setuptools_scm/hg.py +++ b/src/setuptools_scm/hg.py @@ -6,12 +6,11 @@ from pathlib import Path from typing import TYPE_CHECKING from . import Configuration +from ._trace import trace from ._version_cls import Version from .scm_workdir import Workdir from .utils import data_from_mime -from .utils import do_ex from .utils import require_command -from .utils import trace from .version import meta from .version import ScmVersion from .version import tag_to_version @@ -19,6 +18,8 @@ from .version import tag_to_version if TYPE_CHECKING: from . import _types as _t +from ._run_cmd import run as _run + class HgWorkdir(Workdir): COMMAND = "hg" @@ -26,10 +27,10 @@ class HgWorkdir(Workdir): @classmethod def from_potential_worktree(cls, wd: _t.PathT) -> HgWorkdir | None: require_command(cls.COMMAND) - root, err, ret = do_ex("hg root", wd) - if ret: + res = _run("hg root", wd) + if res.returncode: return None - return cls(root) + return cls(res.stdout) def get_meta(self, config: Configuration) -> ScmVersion | None: node: str @@ -48,10 +49,7 @@ class HgWorkdir(Workdir): ["hg", "id", "-T", "{branch}\n{if(dirty, 1, 0)}\n{date|shortdate}"] ).split("\n") dirty = bool(int(dirty_str)) - # todo: fromiso - node_date = datetime.date( - *map(int, (dirty_date if dirty else node_date_str).split("-")) - ) + node_date = datetime.date.fromisoformat(dirty_date if dirty else node_date_str) if node.count("0") == len(node): trace("initial node", self.path) @@ -106,7 +104,8 @@ class HgWorkdir(Workdir): def hg_log(self, revset: str, template: str) -> str: cmd = ["hg", "log", "-r", revset, "-T", template] - return self.do(cmd) + + return _run(cmd, cwd=self.path, check=True).stdout def get_latest_normalizable_tag(self) -> str | None: # Gets all tags containing a '.' (see #229) from oldest to newest @@ -141,9 +140,9 @@ class HgWorkdir(Workdir): def parse(root: _t.PathT, config: Configuration) -> ScmVersion | None: if os.path.exists(os.path.join(root, ".hg/git")): - paths, _, ret = do_ex("hg path", root) - if not ret: - for line in paths.split("\n"): + res = _run(["hg", "path"], root) + if not res.returncode: + for line in res.stdout.split("\n"): if line.startswith("default ="): path = Path(line.split()[2]) if path.name.endswith(".git") or (path / ".git").exists(): diff --git a/src/setuptools_scm/hg_git.py b/src/setuptools_scm/hg_git.py index bde71ec..f7ea883 100644 --- a/src/setuptools_scm/hg_git.py +++ b/src/setuptools_scm/hg_git.py @@ -6,13 +6,12 @@ from datetime import date from datetime import datetime from . import _types as _t +from ._trace import trace from .git import GitWorkdir from .hg import HgWorkdir from .utils import _CmdResult from .utils import do_ex from .utils import require_command -from .utils import trace - _FAKE_GIT_DESCRIBE_ERROR = _CmdResult("<>hg git failed", "", 1) diff --git a/src/setuptools_scm/integration.py b/src/setuptools_scm/integration.py index e9c6c12..e2a033e 100644 --- a/src/setuptools_scm/integration.py +++ b/src/setuptools_scm/integration.py @@ -16,9 +16,8 @@ from ._entrypoints import iter_entry_points from ._integration.setuptools import ( read_dist_name_from_setup_cfg as _read_dist_name_from_setup_cfg, ) +from ._trace import trace from ._version_cls import _validate_version_cls -from .utils import do -from .utils import trace if TYPE_CHECKING: from . import _types as _t @@ -106,11 +105,7 @@ def find_files(path: _t.PathT = "") -> list[str]: iter_entry_points("setuptools_scm.files_command_fallback"), ): command = ep.load() - if isinstance(command, str): - # this technique is deprecated - res = do(ep.load(), path or ".").splitlines() - else: - res = command(path) + res: list[str] = command(path) if res: return res return [] diff --git a/src/setuptools_scm/utils.py b/src/setuptools_scm/utils.py index 52aa5e2..09d8af7 100644 --- a/src/setuptools_scm/utils.py +++ b/src/setuptools_scm/utils.py @@ -3,26 +3,19 @@ utils """ from __future__ import annotations -import os -import platform -import shlex -import subprocess import sys -import textwrap import warnings from types import CodeType from types import FunctionType -from typing import Iterator -from typing import Mapping from typing import NamedTuple from typing import TYPE_CHECKING +from . import _run_cmd +from . import _trace + if TYPE_CHECKING: from . import _types as _t -DEBUG = bool(os.environ.get("SETUPTOOLS_SCM_DEBUG")) -IS_WINDOWS = platform.system() == "Windows" - class _CmdResult(NamedTuple): out: str @@ -30,107 +23,14 @@ class _CmdResult(NamedTuple): returncode: int -def no_git_env(env: Mapping[str, str]) -> dict[str, str]: - # adapted from pre-commit - # Too many bugs dealing with environment variables and GIT: - # https://github.com/pre-commit/pre-commit/issues/300 - # In git 2.6.3 (maybe others), git exports GIT_WORK_TREE while running - # pre-commit hooks - # In git 1.9.1 (maybe others), git exports GIT_DIR and GIT_INDEX_FILE - # while running pre-commit hooks in submodules. - # GIT_DIR: Causes git clone to clone wrong thing - # GIT_INDEX_FILE: Causes 'error invalid object ...' during commit - for k, v in env.items(): - if k.startswith("GIT_"): - trace(k, v) - return { - k: v - for k, v in env.items() - if not k.startswith("GIT_") - or k in ("GIT_EXEC_PATH", "GIT_SSH", "GIT_SSH_COMMAND") - } - - -def avoid_pip_isolation(env: Mapping[str, str]) -> dict[str, str]: - """ - pip build isolation can break Mercurial - (see https://github.com/pypa/pip/issues/10635) - - pip uses PYTHONNOUSERSITE and a path in PYTHONPATH containing "pip-build-env-". - """ - new_env = {k: v for k, v in env.items() if k != "PYTHONNOUSERSITE"} - if "PYTHONPATH" not in new_env: - return new_env - - new_env["PYTHONPATH"] = os.pathsep.join( - [ - path - for path in new_env["PYTHONPATH"].split(os.pathsep) - if "pip-build-env-" not in path - ] - ) - return new_env - - -def trace(*k: object, indent: bool = False) -> None: - if DEBUG: - if indent and len(k) > 1: - k = (k[0],) + tuple(textwrap.indent(str(s), " ") for s in k[1:]) - print(*k, file=sys.stderr, flush=True) - - -def ensure_stripped_str(str_or_bytes: str | bytes) -> str: - if isinstance(str_or_bytes, str): - return str_or_bytes.strip() - else: - return str_or_bytes.decode("utf-8", "surrogateescape").strip() - - -def _run(cmd: _t.CMD_TYPE, cwd: _t.PathT) -> subprocess.CompletedProcess[str]: - return subprocess.run( - cmd, - capture_output=True, - cwd=str(cwd), - env=dict( - avoid_pip_isolation(no_git_env(os.environ)), - # os.environ, - # try to disable i18n - LC_ALL="C", - LANGUAGE="", - HGPLAIN="1", - ), - text=True, - ) +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_ex(cmd: _t.CMD_TYPE, cwd: _t.PathT = ".") -> _CmdResult: - if not DEBUG or not isinstance(cmd, list): - cmd_4_trace = cmd - else: - # 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] - ) - trace("----\ncmd:\n", cmd_4_trace, indent=True) - trace(" in:", cwd) - if os.name == "posix" and not isinstance(cmd, (list, tuple)): - cmd = shlex.split(cmd) - - res = _run(cmd, cwd) - if res.stdout: - trace("out:\n", res.stdout, indent=True) - if res.stderr: - trace("err:\n", res.stderr, indent=True) - if res.returncode: - trace("ret:", res.returncode) - return _CmdResult( - ensure_stripped_str(res.stdout), ensure_stripped_str(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 DEBUG: + if ret and not _trace.DEBUG: print(err) return out @@ -138,10 +38,10 @@ def do(cmd: list[str] | str, cwd: str | _t.PathT = ".") -> str: def data_from_mime(path: _t.PathT) -> dict[str, str]: with open(path, encoding="utf-8") as fp: content = fp.read() - trace("content", repr(content)) + _trace.trace("content", repr(content)) # the complex conditions come from reading pseudo-mime-messages data = dict(x.split(": ", 1) for x in content.splitlines() if ": " in x) - trace("data", data) + _trace.trace("data", data) return data @@ -154,9 +54,9 @@ def function_has_arg(fn: object | FunctionType, argname: str) -> bool: def has_command(name: str, args: list[str] | None = None, warn: bool = True) -> bool: try: cmd = [name, "help"] if args is None else [name, *args] - p = _run(cmd, ".") + p = _run_cmd.run(cmd, ".") except OSError: - trace(*sys.exc_info()) + _trace.trace(*sys.exc_info()) res = False else: res = not p.returncode @@ -167,12 +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) - - -def iter_entry_points( - group: str, name: str | None = None -) -> Iterator[_t.EntrypointProtocol]: - from ._entrypoints import iter_entry_points - - return iter_entry_points(group, name) + raise OSError(f"{name!r} was not found") diff --git a/src/setuptools_scm/version.py b/src/setuptools_scm/version.py index 7c6abd3..36bc7df 100644 --- a/src/setuptools_scm/version.py +++ b/src/setuptools_scm/version.py @@ -28,7 +28,7 @@ if TYPE_CHECKING: from ._version_cls import Version as PkgVersion, _VersionT from . import _version_cls as _v from . import _config -from .utils import trace +from ._trace import trace SEMVER_MINOR = 2 SEMVER_PATCH = 3 diff --git a/testing/conftest.py b/testing/conftest.py index 3928f75..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: @@ -42,7 +43,7 @@ def pytest_addoption(parser: Any) -> None: class DebugMode: def __init__(self, monkeypatch: pytest.MonkeyPatch): self.__monkeypatch = monkeypatch - self.__module = setuptools_scm.utils + self.__module = setuptools_scm._trace __monkeypatch: pytest.MonkeyPatch @@ -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..bf21a47 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: @@ -89,8 +90,8 @@ def test_fallback(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: 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(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_git.py b/testing/test_git.py index 35ea1ec..13a8fec 100644 --- a/testing/test_git.py +++ b/testing/test_git.py @@ -21,9 +21,9 @@ from setuptools_scm import Configuration from setuptools_scm import git from setuptools_scm import integration from setuptools_scm import NonNormalizedVersion +from setuptools_scm._run_cmd import run from setuptools_scm.file_finder_git import git_find_files from setuptools_scm.git import archival_to_version -from setuptools_scm.utils import do from setuptools_scm.utils import has_command from setuptools_scm.version import format_version @@ -69,8 +69,8 @@ setup(use_scm_version={"root": "../..", "relative_to": __file__}) """ ) - 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_root_search_parent_directories( @@ -84,8 +84,8 @@ def test_root_search_parent_directories( setup(use_scm_version={"search_parent_directories": True}) """ ) - 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_git_gone(wd: WorkDir, monkeypatch: pytest.MonkeyPatch) -> None: @@ -285,9 +285,9 @@ def test_git_worktree_support(wd: WorkDir, tmp_path: Path) -> None: worktree = tmp_path / "work_tree" wd("git worktree add -b work-tree %s" % worktree) - res = do([sys.executable, "-m", "setuptools_scm", "ls"], cwd=worktree) - assert "test.txt" in res - assert str(worktree) in res + res = run([sys.executable, "-m", "setuptools_scm", "ls"], cwd=worktree) + assert "test.txt" in res.stdout + assert str(worktree) in res.stdout @pytest.fixture @@ -296,7 +296,7 @@ def shallow_wd(wd: WorkDir, tmp_path: Path) -> Path: wd.commit_testfile() wd.commit_testfile() target = tmp_path / "wd_shallow" - do(["git", "clone", "file://%s" % wd.cwd, str(target), "--depth=1"]) + run(["git", "clone", f"file://{wd.cwd}", target, "--depth=1"], tmp_path, check=True) return target diff --git a/testing/test_integration.py b/testing/test_integration.py index 0ab1548..cba0f98 100644 --- a/testing/test_integration.py +++ b/testing/test_integration.py @@ -10,8 +10,8 @@ import setuptools_scm._integration.setuptools from .wd_wrapper import WorkDir from setuptools_scm import PRETEND_KEY from setuptools_scm import PRETEND_KEY_NAMED +from setuptools_scm._run_cmd import run from setuptools_scm.integration import _warn_on_old_setuptools -from setuptools_scm.utils import do @pytest.fixture @@ -45,8 +45,8 @@ def test_pyproject_support(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> N encoding="utf-8", ) pkg.joinpath("setup.py").write_text("__import__('setuptools').setup()") - res = do([sys.executable, "setup.py", "--version"], pkg) - assert res == "12.34" + res = run([sys.executable, "setup.py", "--version"], pkg) + assert res.stdout == "12.34" PYPROJECT_FILES = { @@ -145,7 +145,7 @@ def testwarn_on_broken_setuptools() -> None: @pytest.mark.issue(611) -def test_distribution_procides_extras() -> None: +def test_distribution_provides_extras() -> None: try: from importlib.metadata import distribution # type: ignore except ImportError: 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/testing/wd_wrapper.py b/testing/wd_wrapper.py index de578c4..1587f82 100644 --- a/testing/wd_wrapper.py +++ b/testing/wd_wrapper.py @@ -67,7 +67,7 @@ class WorkDir: __tracebackhide__ = True from setuptools_scm import get_version - version = get_version(root=str(self.cwd), fallback_root=str(self.cwd), **kw) + version = get_version(root=self.cwd, fallback_root=self.cwd, **kw) print(version) return version @@ -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 [] |