summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonny Pfannschmidt <opensource@ronnypfannschmidt.de>2023-03-11 22:43:44 +0100
committerGitHub <noreply@github.com>2023-03-11 22:43:44 +0100
commit792f61e3ab701cd851d2071885106df581343e0e (patch)
tree03ab91ee3c63e0f5b892dd11f87fc351faa20c2e
parent6d1d966411d5ca98186dd2fb7e22751e1f034dc1 (diff)
parent97ef8752f5d6ae5dd3f4e7997ce6c98caa4e22fb (diff)
downloadsetuptools-scm-792f61e3ab701cd851d2071885106df581343e0e.tar.gz
Merge pull request #808 from RonnyPfannschmidt/ronny/cmd-refactor
refactor: split tracing and command running into own modules
-rw-r--r--.pre-commit-config.yaml3
-rw-r--r--MANIFEST.in1
-rw-r--r--src/setuptools_scm/__init__.py4
-rw-r--r--src/setuptools_scm/_config.py2
-rw-r--r--src/setuptools_scm/_entrypoints.py2
-rw-r--r--src/setuptools_scm/_overrides.py2
-rw-r--r--src/setuptools_scm/_run_cmd.py104
-rw-r--r--src/setuptools_scm/_trace.py30
-rw-r--r--src/setuptools_scm/_types.py3
-rw-r--r--src/setuptools_scm/discover.py2
-rw-r--r--src/setuptools_scm/file_finder.py2
-rw-r--r--src/setuptools_scm/file_finder_git.py16
-rw-r--r--src/setuptools_scm/file_finder_hg.py10
-rw-r--r--src/setuptools_scm/git.py2
-rw-r--r--src/setuptools_scm/hacks.py2
-rw-r--r--src/setuptools_scm/hg.py25
-rw-r--r--src/setuptools_scm/hg_git.py3
-rw-r--r--src/setuptools_scm/integration.py9
-rw-r--r--src/setuptools_scm/utils.py134
-rw-r--r--src/setuptools_scm/version.py2
-rw-r--r--testing/conftest.py7
-rw-r--r--testing/test_basic_api.py17
-rw-r--r--testing/test_git.py18
-rw-r--r--testing/test_integration.py8
-rw-r--r--testing/test_regressions.py25
-rw-r--r--testing/wd_wrapper.py2
-rw-r--r--tox.ini8
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
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 []