summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonny Pfannschmidt <opensource@ronnypfannschmidt.de>2023-02-24 19:38:20 +0100
committerRonny Pfannschmidt <opensource@ronnypfannschmidt.de>2023-03-11 22:06:31 +0100
commita7f7e58cda4b20f24884a1847c273ce7f0c6ba9c (patch)
treeb2350999b80e7d9b77563d1a6c377b91be0dbda6
parent6d1d966411d5ca98186dd2fb7e22751e1f034dc1 (diff)
downloadsetuptools-scm-a7f7e58cda4b20f24884a1847c273ce7f0c6ba9c.tar.gz
refactor: split tracing and command running into own modules
-rw-r--r--MANIFEST.in1
-rw-r--r--src/setuptools_scm/__init__.py2
-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.py96
-rw-r--r--src/setuptools_scm/_trace.py26
-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.py3
-rw-r--r--src/setuptools_scm/file_finder_hg.py2
-rw-r--r--src/setuptools_scm/git.py2
-rw-r--r--src/setuptools_scm/hacks.py2
-rw-r--r--src/setuptools_scm/hg.py2
-rw-r--r--src/setuptools_scm/hg_git.py3
-rw-r--r--src/setuptools_scm/integration.py9
-rw-r--r--src/setuptools_scm/utils.py120
-rw-r--r--src/setuptools_scm/version.py2
-rw-r--r--testing/conftest.py2
19 files changed, 150 insertions, 132 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index 54e9473..11d563c 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
+exclude nextgen
diff --git a/src/setuptools_scm/__init__.py b/src/setuptools_scm/__init__.py
index d6def65..e15eeb1 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:
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..83b0b19
--- /dev/null
+++ b/src/setuptools_scm/_run_cmd.py
@@ -0,0 +1,96 @@
+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,
+) -> subprocess.CompletedProcess[str]:
+ if isinstance(cmd, str):
+ cmd = shlex.split(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,
+ )
+ 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)
+ return res
diff --git a/src/setuptools_scm/_trace.py b/src/setuptools_scm/_trace.py
new file mode 100644
index 0000000..01383a5
--- /dev/null
+++ b/src/setuptools_scm/_trace.py
@@ -0,0 +1,26 @@
+from __future__ import annotations
+
+import os
+import sys
+import textwrap
+
+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 trace_command(cmd: _t.CMD_TYPE, 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]
+ )
+ trace(f"---\n > {cwd}\\$ ", cmd_4_trace, indent=True)
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..c16cff6 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 ._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__)
diff --git a/src/setuptools_scm/file_finder_hg.py b/src/setuptools_scm/file_finder_hg.py
index b750fea..30f28b9 100644
--- a/src/setuptools_scm/file_finder_hg.py
+++ b/src/setuptools_scm/file_finder_hg.py
@@ -4,11 +4,11 @@ import os
import subprocess
from . import _types as _t
+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:
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..c325d0f 100644
--- a/src/setuptools_scm/hg.py
+++ b/src/setuptools_scm/hg.py
@@ -6,12 +6,12 @@ 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
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..2be1654 100644
--- a/src/setuptools_scm/utils.py
+++ b/src/setuptools_scm/utils.py
@@ -3,26 +3,20 @@ 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 +24,15 @@ 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:
- 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
- )
+ 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:
out, err, ret = do_ex(cmd, cwd)
- if ret and not DEBUG:
+ if ret and not _trace.DEBUG:
print(err)
return out
@@ -138,10 +40,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 +56,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
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..b0a4b0e 100644
--- a/testing/conftest.py
+++ b/testing/conftest.py
@@ -42,7 +42,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