Skip to content

Commit

Permalink
Merge branch 'main' into patch
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcinKonowalczyk committed Apr 27, 2024
2 parents be21104 + 261b4ca commit 4158e80
Show file tree
Hide file tree
Showing 20 changed files with 87 additions and 31 deletions.
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Expand Up @@ -5,7 +5,7 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.28.1
rev: 0.28.2
hooks:
- id: check-github-workflows
args: [ "--verbose" ]
Expand All @@ -20,12 +20,12 @@ repos:
- id: tox-ini-fmt
args: ["-p", "fix"]
- repo: https://github.com/tox-dev/pyproject-fmt
rev: "1.7.0"
rev: "1.8.0"
hooks:
- id: pyproject-fmt
additional_dependencies: ["tox>=4.12.1"]
additional_dependencies: ["tox>=4.14.2"]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.3.5"
rev: "v0.4.1"
hooks:
- id: ruff-format
- id: ruff
Expand All @@ -34,7 +34,7 @@ repos:
rev: 1.16.0
hooks:
- id: blacken-docs
additional_dependencies: [black==23.12.1]
additional_dependencies: [black==24.4]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
Expand Down
20 changes: 20 additions & 0 deletions docs/changelog.rst
Expand Up @@ -4,6 +4,26 @@ Release History

.. towncrier release notes start
v4.15.0 (2024-04-26)
--------------------

Features - 4.15.0
~~~~~~~~~~~~~~~~~
- Add support for multiple appending override options (-x, --override) on command line - by :user:`amitschang`. (:issue:`3261`)
- Add support for inverting exit code success criteria using bang (!) (:issue:`3271`)

Bugfixes - 4.15.0
~~~~~~~~~~~~~~~~~
- Fix issue that the leading character ``c`` was dropped from packages in constraints files - by :user:`jugmac00`. (:issue:`3247`)
- Allow appending to ``deps`` with ``--override testenv.deps+=foo`` - by :user:`stefanor`. (:issue:`3256`)
- Fix non-existing branch ``rewrite`` in the documentation to ``main``. (:issue:`3257`)
- Update test typing for build 1.2.0, which has an explicit ``Distribution`` type - by :user:`stefanor`. (:issue:`3260`)
- Fix broken input parsing for ``--discover`` flag. - by :user:`mimre25` (:issue:`3272`)

Improved Documentation - 4.15.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Rephrase ``--discover`` flag's description to avoid confusion between paths and executables. - by :user:`mimre25` (:issue:`3274`)

v4.14.2 (2024-03-22)
--------------------

Expand Down
1 change: 0 additions & 1 deletion docs/changelog/3247.bugfix.rst

This file was deleted.

1 change: 0 additions & 1 deletion docs/changelog/3256.bugfix.rst

This file was deleted.

1 change: 0 additions & 1 deletion docs/changelog/3257.bugfix.rst

This file was deleted.

1 change: 0 additions & 1 deletion docs/changelog/3260.bugfix.rst

This file was deleted.

1 change: 0 additions & 1 deletion docs/changelog/3261.feature.rst

This file was deleted.

12 changes: 11 additions & 1 deletion docs/faq.rst
Expand Up @@ -187,12 +187,22 @@ a given command add a ``-`` prefix to that line (similar syntax to how the GNU `

.. code-block:: ini
[testenv]
commands =
- python -c 'import sys; sys.exit(1)'
python --version
You can also choose to provide a ``!`` prefix instead to purposely invert the exit code, making the line fail if the
command returned exit code 0. Any other exit code is considered a success.

.. code-block:: ini
[testenv]
commands =
! python -c 'import sys; sys.exit(1)'
python --version
Customizing virtual environment creation
----------------------------------------

Expand Down
3 changes: 2 additions & 1 deletion src/tox/config/cli/parser.py
Expand Up @@ -232,7 +232,8 @@ def __call__(
dest="discover",
nargs="+",
metavar="path",
help="for Python discovery first try the Python executables under these paths",
of_type=List[str],
help="for Python discovery first try these Python executables",
default=[],
)
list_deps = sub_parser.add_mutually_exclusive_group()
Expand Down
4 changes: 2 additions & 2 deletions src/tox/config/loader/convert.py
Expand Up @@ -64,13 +64,13 @@ def _to_typing(self, raw: T, of_type: type[V], factory: Factory[V]) -> V: # noq
elif origin == Union: # handle Optional values
args: list[type[Any]] = of_type.__args__ # type: ignore[attr-defined]
none = type(None)
if len(args) == 2 and none in args: # type: ignore[comparison-overlap] # noqa: PLR2004
if len(args) == 2 and none in args: # noqa: PLR2004
if isinstance(raw, str):
raw = raw.strip() # type: ignore[assignment]
if not raw:
result = None
else:
new_type = next(i for i in args if i != none) # type: ignore[comparison-overlap] # pragma: no cover
new_type = next(i for i in args if i != none) # pragma: no cover
result = self.to(raw, new_type, factory)
elif origin in {Literal, type(Literal)}:
choice = of_type.__args__ # type: ignore[attr-defined]
Expand Down
11 changes: 8 additions & 3 deletions src/tox/config/types.py
Expand Up @@ -16,15 +16,20 @@ def __init__(self, args: list[str]) -> None:
:param args: the command line arguments (first value can be ``-`` to indicate ignore the exit code)
"""
self.ignore_exit_code: bool = args[0] == "-" #: a flag indicating if the exit code should be ignored
self.args: list[str] = args[1:] if self.ignore_exit_code else args #: the command line arguments
self.invert_exit_code: bool = args[0] == "!" #: a flag for flipped exit code (non-zero = success, 0 = error)
self.args: list[str] = (
args[1:] if self.ignore_exit_code or self.invert_exit_code else args
) #: the command line arguments

def __repr__(self) -> str:
return f"{type(self).__name__}(args={(['-'] if self.ignore_exit_code else []) + self.args!r})"
args = (["-"] if self.ignore_exit_code else ["!"] if self.invert_exit_code else []) + self.args
return f"{type(self).__name__}(args={args!r})"

def __eq__(self, other: object) -> bool:
return type(self) == type(other) and (self.args, self.ignore_exit_code) == (
return type(self) == type(other) and (self.args, self.ignore_exit_code, self.invert_exit_code) == (
other.args, # type: ignore[attr-defined]
other.ignore_exit_code, # type: ignore[attr-defined]
other.invert_exit_code, # type: ignore[attr-defined]
)

def __ne__(self, other: object) -> bool:
Expand Down
6 changes: 6 additions & 0 deletions src/tox/execute/api.py
Expand Up @@ -252,6 +252,12 @@ def assert_success(self) -> None:
self._assert_fail()
self.log_run_done(logging.INFO)

def assert_failure(self) -> None:
"""Assert that the execution failed."""
if self.exit_code is not None and self.exit_code == self.OK:
self._assert_fail()
self.log_run_done(logging.INFO)

def _assert_fail(self) -> NoReturn:
if self.show_on_standard is False:
if self.out:
Expand Down
5 changes: 4 additions & 1 deletion src/tox/session/cmd/run/single.py
Expand Up @@ -112,7 +112,10 @@ def run_command_set(
)
outcomes.append(current_outcome)
try:
current_outcome.assert_success()
if cmd.invert_exit_code:
current_outcome.assert_failure()
else:
current_outcome.assert_success()
except SystemExit as exception:
if cmd.ignore_exit_code:
logging.warning("command failed but is marked ignore outcome so handling it as success")
Expand Down
2 changes: 1 addition & 1 deletion src/tox/session/cmd/show_config.py
Expand Up @@ -95,7 +95,7 @@ def print_key_value(is_colored: bool, key: str, value: str, multi_line: bool = F


def print_conf(is_colored: bool, conf: ConfigSet, keys: Iterable[str]) -> None: # noqa: FBT001
for key in keys if keys else conf:
for key in keys or conf:
if key not in conf:
continue
key = conf.primary_key(key) # noqa: PLW2901
Expand Down
5 changes: 4 additions & 1 deletion src/tox/tox_env/python/pip/pip_install.py
@@ -1,6 +1,7 @@
from __future__ import annotations

import logging
import operator
from collections import defaultdict
from pathlib import Path
from typing import TYPE_CHECKING, Any, Callable, Sequence
Expand Down Expand Up @@ -132,7 +133,9 @@ def _install_requirement_file(self, arguments: PythonDeps, section: str, of_type
if not eq: # pragma: no branch
if old is not None:
self._recreate_if_diff("install flag(s)", new_options, old["options"], lambda i: i)
self._recreate_if_diff("constraint(s)", new_constraints, old["constraints"], lambda i: i[3:])
self._recreate_if_diff(
"constraint(s)", new_constraints, old["constraints"], operator.itemgetter(slice(3, None))
)
missing_requirement = set(old["requirements"]) - set(new_requirements)
if missing_requirement:
msg = f"requirements removed: {' '.join(missing_requirement)}"
Expand Down
2 changes: 1 addition & 1 deletion src/tox/util/cpu.py
Expand Up @@ -10,7 +10,7 @@ def auto_detect_cpus() -> int:
n: int | None = multiprocessing.cpu_count()
except NotImplementedError:
n = None
return n if n else 1
return n or 1


__all__ = ("auto_detect_cpus",)
3 changes: 2 additions & 1 deletion tests/config/cli/test_cli_env_var.py
Expand Up @@ -84,6 +84,7 @@ def test_env_var_exhaustive_parallel_values(
monkeypatch.setenv("TOX_PARALLEL", "3")
monkeypatch.setenv("TOX_PARALLEL_LIVE", "no")
monkeypatch.setenv("TOX_OVERRIDE", "a=b;c=d")
monkeypatch.setenv("TOX_DISCOVER", "/foo/bar;/bar/baz;/baz/foo")

options = get_options()
assert vars(options.parsed) == {
Expand All @@ -93,7 +94,7 @@ def test_env_var_exhaustive_parallel_values(
"default_runner": "virtualenv",
"develop": False,
"devenv_path": None,
"discover": [],
"discover": ["/foo/bar", "/bar/baz", "/baz/foo"],
"env": CliEnv(["py37", "py36"]),
"force_dep": [],
"hash_seed": ANY,
Expand Down
12 changes: 11 additions & 1 deletion tests/config/test_types.py
Expand Up @@ -6,15 +6,24 @@
def tests_command_repr() -> None:
cmd = Command(["python", "-m", "pip", "list"])
assert repr(cmd) == "Command(args=['python', '-m', 'pip', 'list'])"
assert cmd.invert_exit_code is False
assert cmd.ignore_exit_code is False


def tests_command_repr_ignore() -> None:
cmd = Command(["-", "python", "-m", "pip", "list"])
assert repr(cmd) == "Command(args=['-', 'python', '-m', 'pip', 'list'])"
assert cmd.invert_exit_code is False
assert cmd.ignore_exit_code is True


def tests_command_repr_invert() -> None:
cmd = Command(["!", "python", "-m", "pip", "list"])
assert repr(cmd) == "Command(args=['!', 'python', '-m', 'pip', 'list'])"
assert cmd.invert_exit_code is True
assert cmd.ignore_exit_code is False


def tests_command_eq() -> None:
cmd_1 = Command(["python", "-m", "pip", "list"])
cmd_2 = Command(["python", "-m", "pip", "list"])
Expand All @@ -24,7 +33,8 @@ def tests_command_eq() -> None:
def tests_command_ne() -> None:
cmd_1 = Command(["python", "-m", "pip", "list"])
cmd_2 = Command(["-", "python", "-m", "pip", "list"])
assert cmd_1 != cmd_2
cmd_3 = Command(["!", "python", "-m", "pip", "list"])
assert cmd_1 != cmd_2 != cmd_3


def tests_env_list_repr() -> None:
Expand Down
6 changes: 4 additions & 2 deletions tests/util/test_ci.py
@@ -1,5 +1,7 @@
from __future__ import annotations

import operator

import pytest

from tox.util.ci import _ENV_VARS, is_ci # noqa: PLC2701
Expand All @@ -22,7 +24,7 @@
"TEAMCITY_VERSION": None, # TeamCity
"TRAVIS": "true", # Travis CI
}.items(),
ids=lambda v: v[0],
ids=operator.itemgetter(0),
)
def test_is_ci(env_var: tuple[str, str | None], monkeypatch: pytest.MonkeyPatch) -> None:
for var in _ENV_VARS:
Expand All @@ -41,7 +43,7 @@ def test_is_ci(env_var: tuple[str, str | None], monkeypatch: pytest.MonkeyPatch)
"GITHUB_ACTIONS": "", # GitHub Actions
"TRAVIS": "", # Travis CI
}.items(),
ids=lambda v: v[0],
ids=operator.itemgetter(0),
)
def test_is_ci_bad_set(env_var: tuple[str, str], monkeypatch: pytest.MonkeyPatch) -> None:
for var in _ENV_VARS:
Expand Down
12 changes: 6 additions & 6 deletions tox.ini
Expand Up @@ -40,7 +40,7 @@ commands =
description = format the code base to adhere to our styles, and complain about what we cannot do automatically
skip_install = true
deps =
pre-commit>=3.6
pre-commit>=3.7
pass_env =
{[testenv]passenv}
PROGRAMDATA
Expand All @@ -51,7 +51,7 @@ commands =
[testenv:type]
description = run type check on code base
deps =
mypy==1.8
mypy==1.9
types-cachetools>=5.3.0.7
types-chardet>=5.0.4.6
commands =
Expand All @@ -71,9 +71,9 @@ commands =
description = check that the long description is valid
skip_install = true
deps =
build[virtualenv]>=1.0.3
build[virtualenv]>=1.2.1
check-wheel-contents>=0.6
twine>=4.0.2
twine>=5
commands =
python -m build -o {envtmpdir} -s -w .
twine check {envtmpdir}{/}*
Expand All @@ -83,8 +83,8 @@ commands =
description = do a release, required posarg of the version number
skip_install = true
deps =
gitpython>=3.1.41
packaging>=23.2
gitpython>=3.1.43
packaging>=24
towncrier>=23.11
commands =
python {toxinidir}/tasks/release.py --version {posargs}
Expand Down

0 comments on commit 4158e80

Please sign in to comment.