Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: tox-dev/tox
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 4.17.1
Choose a base ref
...
head repository: tox-dev/tox
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4.18.0
Choose a head ref
  • 4 commits
  • 11 files changed
  • 4 contributors

Commits on Aug 11, 2024

  1. Fix #3278 - Boost temporary directories cleanup in tests (#3323)

    * Fix #3278 - Boost temporary directories cleanup in tests
    
    * [pre-commit.ci] auto fixes from pre-commit.com hooks
    
    for more information, see https://pre-commit.ci
    
    ---------
    
    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    ziima and pre-commit-ci[bot] authored Aug 11, 2024
    Copy the full SHA
    add99ed View commit details

Commits on Aug 13, 2024

  1. Fix absolute base python paths conflicting (#3325)

    gaborbernat authored Aug 13, 2024
    Copy the full SHA
    1ee4a33 View commit details
  2. Fix #3318 - Suppress spinner in parallel runs in CI (#3321)

    Co-authored-by: Bernát Gábor <bgabor8@bloomberg.net>
    Co-authored-by: Bernát Gábor <gaborjbernat@gmail.com>
    3 people authored Aug 13, 2024
    Copy the full SHA
    3b3628d View commit details
  3. release 4.18.0

    Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
    gaborbernat committed Aug 13, 2024
    Copy the full SHA
    ea72694 View commit details
3 changes: 2 additions & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ on:
workflow_dispatch:
push:
branches: ["main"]
tags-ignore: [ "**" ]
tags-ignore: ["**"]
pull_request:
schedule:
- cron: "0 8 * * *"
@@ -76,6 +76,7 @@ jobs:
- windows-latest
exclude:
- { os: windows-latest, tox_env: pkg_meta }
- { os: windows-latest, tox_env: docs }
steps:
- uses: actions/checkout@v4
with:
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ jobs:

release:
needs:
- build
- build
runs-on: ubuntu-latest
environment:
name: release
13 changes: 10 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ repos:
rev: 0.29.1
hooks:
- id: check-github-workflows
args: [ "--verbose" ]
args: ["--verbose"]
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
@@ -24,7 +24,7 @@ repos:
hooks:
- id: pyproject-fmt
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.5.6"
rev: "v0.5.7"
hooks:
- id: ruff-format
- id: ruff
@@ -33,11 +33,18 @@ repos:
rev: 1.18.0
hooks:
- id: blacken-docs
additional_dependencies: [black==24.4.2]
additional_dependencies: [black==24.8]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
- id: rst-backticks
- repo: https://github.com/rbubley/mirrors-prettier
rev: "v3.3.3" # Use the sha / tag you want to point at
hooks:
- id: prettier
additional_dependencies:
- prettier@3.3.3
- "@prettier/plugin-xml@3.4.1"
- repo: local
hooks:
- id: changelogs-rst
12 changes: 12 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -4,6 +4,18 @@ Release History

.. towncrier release notes start
v4.18.0 (2024-08-13)
--------------------

Features - 4.17.2
~~~~~~~~~~~~~~~~~
- Suppress spinner in parallel runs in CI - by :user:`ziima`. (:issue:`3318`)

Bugfixes - 4.17.2
~~~~~~~~~~~~~~~~~
- Boost temporary directories cleanup in tests - by :user:`ziima`. (:issue:`3278`)
- Fix absolute base python paths conflicting - by :user:`gaborbernat`. (:issue:`3325`)

v4.17.1 (2024-08-07)
--------------------

5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -128,7 +128,8 @@ lint.ignore = [
"D", # ignore documentation for now
"D203", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible
"D212", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible
"DOC201", # broken with sphinx docs
"DOC201", # no restructuredtext support yet
"DOC402", # no restructuredtext support yet
"DOC501", # broken with sphinx docs
"INP001", # no implicit namespaces here
"ISC001", # conflicts with formatter
@@ -169,6 +170,8 @@ testpaths = [
"tests",
]
addopts = "--tb=auto -ra --showlocals --no-success-flaky-report"
# Keep temporary directories only for failed or errored tests.
tmp_path_retention_policy = "failed"

[tool.coverage]
html.show_contexts = true
11 changes: 9 additions & 2 deletions src/tox/session/cmd/run/parallel.py
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@

from tox.plugin import impl
from tox.session.env_select import CliEnv, register_env_select_flags
from tox.util.ci import is_ci
from tox.util.cpu import auto_detect_cpus

from .common import env_run_create_flags, execute
@@ -28,7 +29,7 @@ def tox_add_option(parser: ToxParser) -> None:
our = parser.add_command("run-parallel", ["p"], "run environments in parallel", run_parallel)
register_env_select_flags(our, default=CliEnv())
env_run_create_flags(our, mode="run-parallel")
parallel_flags(our, default_parallel=DEFAULT_PARALLEL)
parallel_flags(our, default_parallel=DEFAULT_PARALLEL, default_spinner=is_ci())


def parse_num_processes(str_value: str) -> int | None:
@@ -51,6 +52,8 @@ def parallel_flags(
our: ArgumentParser,
default_parallel: int | str,
no_args: bool = False, # noqa: FBT001, FBT002
*,
default_spinner: bool = False,
) -> None:
our.add_argument(
"-p",
@@ -75,7 +78,11 @@ def parallel_flags(
"--parallel-no-spinner",
action="store_true",
dest="parallel_no_spinner",
help="run tox environments in parallel, but don't show the spinner, implies --parallel",
default=default_spinner,
help=(
"run tox environments in parallel, but don't show the spinner, implies --parallel. "
"Disabled by default if CI is detected (not in legacy API)."
),
)


21 changes: 18 additions & 3 deletions src/tox/tox_env/python/api.py
Original file line number Diff line number Diff line change
@@ -15,7 +15,6 @@
from tox.tox_env.errors import Fail, Recreate, Skip

if TYPE_CHECKING:

from tox.config.main import Config


@@ -169,9 +168,14 @@ def _validate_base_python(
if env_base_python is not None:
spec_name = PythonSpec.from_string_spec(env_base_python)
for base_python in base_pythons:
if Path(base_python).is_absolute():
return [base_python]
spec_base = PythonSpec.from_string_spec(base_python)
if spec_base.path is not None:
path = Path(spec_base.path).absolute()
if str(spec_base.path) == sys.executable:
ver, is_64 = sys.version_info, sys.maxsize != 2**32
spec_base = PythonSpec.from_string_spec(f"{sys.implementation}{ver.major}{ver.minor}-{is_64}")
else:
spec_base = cls.python_spec_for_path(path)
if any(
getattr(spec_base, key) != getattr(spec_name, key)
for key in ("implementation", "major", "minor", "micro", "architecture")
@@ -184,6 +188,17 @@ def _validate_base_python(
raise Fail(msg)
return base_pythons

@classmethod
@abstractmethod
def python_spec_for_path(cls, path: Path) -> PythonSpec:
"""
Get the spec for an absolute path to a Python executable.
:param path: the path investigated
:return: the found spec
"""
raise NotImplementedError

@abstractmethod
def env_site_package_dir(self) -> Path:
"""
35 changes: 33 additions & 2 deletions src/tox/tox_env/python/virtual_env/api.py
Original file line number Diff line number Diff line change
@@ -4,11 +4,14 @@

import os
import sys
from abc import ABC
from pathlib import Path
from typing import TYPE_CHECKING, Any, cast

from virtualenv import __version__ as virtualenv_version
from virtualenv import session_via_cli
from virtualenv import app_data, session_via_cli
from virtualenv.discovery import cached_py_info
from virtualenv.discovery.py_spec import PythonSpec

from tox.config.loader.str_convert import StrConvert
from tox.execute.local_sub_process import LocalSubProcessExecutor
@@ -17,13 +20,14 @@

if TYPE_CHECKING:
from virtualenv.create.creator import Creator
from virtualenv.discovery.py_info import PythonInfo as VirtualenvPythonInfo
from virtualenv.run.session import Session

from tox.execute.api import Execute
from tox.tox_env.api import ToxEnvCreateArgs


class VirtualEnv(Python):
class VirtualEnv(Python, ABC):
"""A python executor that uses the virtualenv project with pip."""

def __init__(self, create_args: ToxEnvCreateArgs) -> None:
@@ -167,3 +171,30 @@ def environment_variables(self) -> dict[str, str]:
environment_variables = super().environment_variables
environment_variables["VIRTUAL_ENV"] = str(self.conf["env_dir"])
return environment_variables

@classmethod
def python_spec_for_path(cls, path: Path) -> PythonSpec:
"""
Get the spec for an absolute path to a Python executable.
:param path: the path investigated
:return: the found spec
"""
info = cls.get_virtualenv_py_info(path)
return PythonSpec.from_string_spec(
f"{info.implementation}{info.version_info.major}{info.version_info.minor}-{info.architecture}"
)

@staticmethod
def get_virtualenv_py_info(path: Path) -> VirtualenvPythonInfo:
"""
Get the version info for an absolute path to a Python executable.
:param path: the path investigated
:return: the found information (cached)
"""
return cached_py_info.from_exe(
cached_py_info.PythonInfo,
app_data.make_app_data(None, read_only=False, env=os.environ),
str(path),
)
12 changes: 12 additions & 0 deletions tests/session/cmd/test_legacy.py
Original file line number Diff line number Diff line change
@@ -121,6 +121,18 @@ def test_legacy_run_sequential(tox_project: ToxProjectCreator, mocker: MockerFix
assert run_sequential.call_count == 1


def test_legacy_run_sequential_ci(
tox_project: ToxProjectCreator, mocker: MockerFixture, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test legacy run sequential in CI by default."""
run_sequential = mocker.patch("tox.session.cmd.legacy.run_sequential")
monkeypatch.setenv("CI", "1")

tox_project({"tox.ini": ""}).run("le", "-e", "py")

assert run_sequential.call_count == 1


def test_legacy_help(tox_project: ToxProjectCreator) -> None:
outcome = tox_project({"tox.ini": ""}).run("le", "-h")
outcome.assert_success()
17 changes: 17 additions & 0 deletions tests/session/cmd/test_parallel.py
Original file line number Diff line number Diff line change
@@ -186,6 +186,23 @@ def test_parallel_no_spinner(tox_project: ToxProjectCreator) -> None:
)


def test_parallel_no_spinner_ci(
tox_project: ToxProjectCreator, mocker: MockerFixture, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Ensure spinner is disabled by default in CI."""
mocked = mocker.patch.object(parallel, "execute")
monkeypatch.setenv("CI", "1")

tox_project({"tox.ini": ""}).run("p")

mocked.assert_called_once_with(
mock.ANY,
max_workers=None,
has_spinner=False,
live=False,
)


def test_parallel_no_spinner_legacy(tox_project: ToxProjectCreator) -> None:
with mock.patch.object(parallel, "execute") as mocked:
tox_project({"tox.ini": ""}).run("--parallel-no-spinner")
19 changes: 0 additions & 19 deletions tests/tox_env/python/test_python_api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import os
import sys
from typing import TYPE_CHECKING, Callable
from unittest.mock import patch
@@ -126,24 +125,6 @@ def test_base_python_env_no_conflict(env: str, base_python: list[str], ignore_co
assert result is base_python


@pytest.mark.parametrize(
("env", "base_python", "platform"),
[
("py312-unix", ["/opt/python312/bin/python"], "posix"),
("py312-win", [r"C:\Program Files\Python312\python.exe"], "nt"),
("py311-win", [r"\\a\python311\python.exe"], "nt"),
("py310-win", [r"\\?\UNC\a\python310\python.exe"], "nt"),
("py310", ["//a/python310/bin/python"], None),
],
ids=lambda a: "|".join(a) if isinstance(a, list) else str(a),
)
def test_base_python_absolute(env: str, base_python: list[str], platform: str | None) -> None:
if platform and platform != os.name:
pytest.skip(f"Not applicable to this platform. ({platform} != {os.name})")
result = Python._validate_base_python(env, base_python, False) # noqa: SLF001
assert result == base_python


@pytest.mark.parametrize("ignore_conflict", [True, False])
@pytest.mark.parametrize(
("env", "base_python", "expected", "conflict"),