Skip to content

Commit

Permalink
Allow extending lists with --override foo+=bar
Browse files Browse the repository at this point in the history
Allow appending to a list with += syntax, instead of replacing the
existing value.

Fixes: #3087
  • Loading branch information
stefanor committed Aug 11, 2023
1 parent b40dc3f commit 9c66027
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 4 deletions.
3 changes: 3 additions & 0 deletions docs/changelog/3088.append-overrides.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
``--override`` can now take options in the form of ``foo+=bar`` which
will append ``bar`` to the end of an existing list, rather than
replacing it.
16 changes: 13 additions & 3 deletions src/tox/config/loader/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ def __init__(self, value: str) -> None:
if not equal:
msg = f"override {value} has no = sign in it"
raise ArgumentTypeError(msg)

self.append = False
if key.endswith("+"): # key += value appends to a list
key = key[:-1]
self.append = True

self.namespace, _, self.key = key.rpartition(".")

def __repr__(self) -> str:
Expand Down Expand Up @@ -117,10 +123,14 @@ def load( # noqa: PLR0913
:param args: the config load arguments
:return: the converted type
"""
if key in self.overrides:
return _STR_CONVERT.to(self.overrides[key].value, of_type, factory)
override = self.overrides.get(key)
if override and not override.append:
return _STR_CONVERT.to(override.value, of_type, factory)
raw = self.load_raw(key, conf, args.env_name)
return self.build(key, of_type, factory, conf, raw, args)
converted = self.build(key, of_type, factory, conf, raw, args)
if override and override.append:
converted += _STR_CONVERT.to(override.value, of_type, factory)
return converted

def build( # noqa: PLR0913
self,
Expand Down
12 changes: 12 additions & 0 deletions tests/config/loader/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ def test_override_add(flag: str) -> None:
assert value.key == "magic"
assert value.value == "true"
assert not value.namespace
assert value.append == False


@pytest.mark.parametrize("flag", ["-x", "--override"])
def test_override_append(flag: str) -> None:
parsed, _, __, ___, ____ = get_options(flag, "magic+=true")
assert len(parsed.override) == 1
value = parsed.override[0]
assert value.key == "magic"
assert value.value == "true"
assert not value.namespace
assert value.append == True


def test_override_equals() -> None:
Expand Down
13 changes: 12 additions & 1 deletion tests/config/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

from tox.config.loader.api import Override
from tox.config.loader.memory import MemoryLoader
Expand Down Expand Up @@ -64,6 +64,17 @@ def test_config_override_wins_memory_loader(tox_ini_conf: ToxIniCreator) -> None
assert conf["c"] == "ok"


def test_config_override_appends(tox_ini_conf: ToxIniCreator) -> None:
example = """
[testenv]
passenv = foo
"""
conf = tox_ini_conf(example, override=[Override("testenv.passenv+=bar")]).get_env("testenv")
conf.add_config("passenv", of_type=List[str], default=[], desc="desc")
print(conf["passenv"])
assert conf["passenv"] == ["foo", "bar"]


def test_args_are_paths_when_disabled(tox_project: ToxProjectCreator) -> None:
ini = "[testenv]\npackage=skip\ncommands={posargs}\nargs_are_paths=False"
project = tox_project({"tox.ini": ini, "w": {"a.txt": "a"}})
Expand Down

0 comments on commit 9c66027

Please sign in to comment.