File: utils.py

package info (click to toggle)
tox-current-env 0.0.16-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 296 kB
  • sloc: python: 1,672; sh: 8; makefile: 6
file content (135 lines) | stat: -rw-r--r-- 3,967 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import configparser
import contextlib
import functools
import os
import pathlib
import re
import subprocess
import sys
from configparser import ConfigParser

import pytest
from packaging.version import parse as ver

PYTHON_VERSION_DOT = f"{sys.version_info[0]}.{sys.version_info[1]}"
PYTHON_VERSION_NODOT = f"{sys.version_info[0]}{sys.version_info[1]}"
NATIVE_TOXENV = f"py{PYTHON_VERSION_NODOT}"
NATIVE_SITE_PACKAGES = f"lib/python{PYTHON_VERSION_DOT}/site-packages"
NATIVE_EXECUTABLE = str(pathlib.Path(sys.executable).resolve())
FIXTURES_DIR = pathlib.Path(__file__).parent / "fixtures"
DOT_TOX = pathlib.Path("./.tox")


def _exec_prefix(executable):
    """Returns sys.exec_prefix for the given executable"""
    cmd = (executable, "-c", "import sys; print(sys.exec_prefix)")
    return subprocess.check_output(cmd, encoding="utf-8").strip()


NATIVE_EXEC_PREFIX = _exec_prefix(NATIVE_EXECUTABLE)
NATIVE_EXEC_PREFIX_MSG = f"{NATIVE_EXEC_PREFIX} is the exec_prefix"


def tox(*args, quiet=True, **kwargs):
    kwargs.setdefault("encoding", "utf-8")
    kwargs.setdefault("stdout", subprocess.PIPE)
    kwargs.setdefault("stderr", subprocess.PIPE)
    kwargs.setdefault("check", True)
    kwargs.setdefault("cwd", os.getcwd())
    q = ("-q",) if quiet else ()
    env = dict(os.environ)
    env.pop("TOX_WORK_DIR", None)
    kwargs["env"] = {**env, **kwargs.get("env", {})}
    try:
        print("current", os.getcwd(), "running in", kwargs["cwd"])
        cp = subprocess.run((sys.executable, "-m", "tox") + q + args, **kwargs)
    except subprocess.CalledProcessError as e:
        print(e.stdout, file=sys.stdout)
        print(e.stderr, file=sys.stderr)
        raise
    print(cp.stdout, file=sys.stdout)
    print(cp.stderr, file=sys.stderr)
    return cp


TOX_VERSION = ver(tox("--version").stdout.split(" ")[0].split("+")[0])
TOX4 = TOX_VERSION.major == 4


@contextlib.contextmanager
def modify_config(tox_ini_path):
    """Context manager that allows modifying the given Tox config file

    A statement like::

        with prepare_config(projdir) as config:

    will make `config` a ConfigParser instance that is saved at the end
    of the `with` block.
    """
    config = configparser.ConfigParser()
    config.read(tox_ini_path)
    yield config
    with open(tox_ini_path, "w") as tox_ini_file:
        config.write(tox_ini_file)


@functools.lru_cache(maxsize=8)
def is_available(python):
    try:
        subprocess.run((python, "--version"))
    except FileNotFoundError:
        return False
    return True


@functools.lru_cache()
def drop_unsupported_pythons(envlist):
    return envlist[len("py36,py37,"):] if TOX4 else envlist


@functools.lru_cache()
def envs_from_tox_ini():
    cp = ConfigParser()
    cp.read(FIXTURES_DIR / "tox.ini")
    envlist = drop_unsupported_pythons(cp["tox"]["envlist"])
    return envlist.split(",")


def tox_footer(envs=None, spaces=8):
    if envs is None:
        envs = envs_from_tox_ini()
    elif isinstance(envs, str):
        envs = [envs]

    default_indent = " " * spaces

    if TOX4:
        result = ""
    else:
        result = "___________________________________ summary ____________________________________\n"

    for i, env in enumerate(envs):
        if TOX4:
            # Skip indentation for the first line
            indent = default_indent if i > 0 else ""
            result += f"{indent}  {env}: OK\n"
        else:
            result += f"{default_indent}  {env}: commands succeeded\n"

    result += f"{default_indent}  congratulations :)"

    return result


def prep_tox_output(output):
    """Remove time info from tox output"""
    result = re.sub(r" \((\d+\.\d+|\d+) seconds\)", "", output)
    result = re.sub(r" ✔ in (\d+\.\d+|\d+) seconds", "", result)
    return result


needs_all_pythons = pytest.mark.skipif(
    not all((is_available(f"python3.{x}") for x in range(6, 12))),
    reason="This test needs all pythons from 3.6 to 3.11 available in $PATH",
)