Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow appending to deps with the command line #3259

Merged
merged 3 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog/3256.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow appending to ``deps`` with ``--override testenv.deps+=foo`` - by :user:`stefanor`.
3 changes: 3 additions & 0 deletions src/tox/config/loader/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import TYPE_CHECKING, Any, List, Mapping, TypeVar

from tox.plugin import impl
from tox.tox_env.python.pip.req_file import PythonDeps

from .convert import Convert, Factory
from .str_convert import StrConvert
Expand Down Expand Up @@ -148,6 +149,8 @@ def load( # noqa: PLR0913
converted.update(converted_override)
elif isinstance(converted, SetEnv) and isinstance(converted_override, SetEnv):
converted.update(converted_override, override=True)
elif isinstance(converted, PythonDeps) and isinstance(converted_override, PythonDeps):
converted += converted_override
else:
msg = "Only able to append to lists and dicts"
raise ValueError(msg)
Expand Down
4 changes: 4 additions & 0 deletions src/tox/tox_env/python/pip/req_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ def unroll(self) -> tuple[list[str], list[str]]:
self._unroll = result_opts, result_req
return self._unroll

def __iadd__(self, other: PythonDeps) -> PythonDeps: # noqa: PYI034
self._raw += "\n" + other._raw
return self

@classmethod
def factory(cls, root: Path, raw: object) -> PythonDeps:
if not isinstance(raw, str):
Expand Down
33 changes: 33 additions & 0 deletions tests/config/test_main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import os
from functools import partial
from pathlib import Path
from typing import TYPE_CHECKING, List

Expand All @@ -9,6 +10,7 @@
from tox.config.loader.api import Override
from tox.config.loader.memory import MemoryLoader
from tox.config.sets import ConfigSet
from tox.tox_env.python.pip.req_file import PythonDeps

if TYPE_CHECKING:
from tests.conftest import ToxIniCreator
Expand Down Expand Up @@ -98,6 +100,37 @@ def test_config_override_appends_to_empty_setenv(tox_ini_conf: ToxIniCreator) ->
assert conf["setenv"].load("foo") == "bar"


def test_config_override_appends_to_pythondeps(tox_ini_conf: ToxIniCreator, tmp_path: Path) -> None:
example = """
[testenv]
deps = foo
"""
conf = tox_ini_conf(example, override=[Override("testenv.deps+=bar")]).get_env("testenv")
conf.add_config(
"deps",
of_type=PythonDeps,
factory=partial(PythonDeps.factory, tmp_path),
default=PythonDeps("", root=tmp_path),
desc="desc",
)
assert conf["deps"].lines() == ["foo", "bar"]


def test_config_override_appends_to_empty_pythondeps(tox_ini_conf: ToxIniCreator, tmp_path: Path) -> None:
example = """
[testenv]
"""
conf = tox_ini_conf(example, override=[Override("testenv.deps+=bar")]).get_env("testenv")
conf.add_config(
"deps",
of_type=PythonDeps,
factory=partial(PythonDeps.factory, tmp_path),
default=PythonDeps("", root=tmp_path),
desc="desc",
)
assert conf["deps"].lines() == ["bar"]


def test_config_override_cannot_append(tox_ini_conf: ToxIniCreator) -> None:
example = """
[testenv]
Expand Down
7 changes: 7 additions & 0 deletions tests/tox_env/python/pip/test_req_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,10 @@ def test_opt_only_req_file(tmp_path: Path) -> None:
python_deps = PythonDeps(raw="-rr.txt", root=tmp_path)
assert not python_deps.requirements
assert python_deps.options == Namespace(features_enabled=["fast-deps"])


def test_req_iadd(tmp_path: Path) -> None:
a = PythonDeps(raw="foo", root=tmp_path)
b = PythonDeps(raw="bar", root=tmp_path)
a += b
assert a.lines() == ["foo", "bar"]