From 6b8e83aebec88743ca4a3b50379ddd9b21afa36c Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Mon, 21 Aug 2023 08:57:45 -0700 Subject: [PATCH] Replace undefined settings with overrides when appending (#3101) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bernát Gábor --- docs/changelog/3100.bugfix.rst | 1 + src/tox/config/loader/api.py | 28 +++++++++++++++++----------- tests/config/test_main.py | 11 +++++++++++ 3 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 docs/changelog/3100.bugfix.rst diff --git a/docs/changelog/3100.bugfix.rst b/docs/changelog/3100.bugfix.rst new file mode 100644 index 000000000..5997bbbae --- /dev/null +++ b/docs/changelog/3100.bugfix.rst @@ -0,0 +1 @@ +``--override foo+=bar`` appending syntax will now work correctly when ``foo`` wasn't defined in ``tox.ini``. diff --git a/src/tox/config/loader/api.py b/src/tox/config/loader/api.py index 30af68a75..5ece578e4 100644 --- a/src/tox/config/loader/api.py +++ b/src/tox/config/loader/api.py @@ -80,7 +80,7 @@ class Loader(Convert[T]): def __init__(self, section: Section, overrides: list[Override]) -> None: self._section = section - self.overrides = {o.key: o for o in overrides} + self.overrides: dict[str, Override] = {o.key: o for o in overrides} self.parent: Loader[Any] | None = None @property @@ -130,18 +130,24 @@ def load( # noqa: PLR0913 from tox.config.set_env import SetEnv 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) + if override: + converted_override = _STR_CONVERT.to(override.value, of_type, factory) + if not override.append: + return converted_override + try: + raw = self.load_raw(key, conf, args.env_name) + except KeyError: + if override: + return converted_override + raise converted = self.build(key, of_type, factory, conf, raw, args) if override and override.append: - appends = _STR_CONVERT.to(override.value, of_type, factory) - if isinstance(converted, list) and isinstance(appends, list): - converted += appends - elif isinstance(converted, dict) and isinstance(appends, dict): - converted.update(appends) - elif isinstance(converted, SetEnv) and isinstance(appends, SetEnv): - converted.update(appends, override=True) + if isinstance(converted, list) and isinstance(converted_override, list): + converted += converted_override + elif isinstance(converted, dict) and isinstance(converted_override, dict): + converted.update(converted_override) + elif isinstance(converted, SetEnv) and isinstance(converted_override, SetEnv): + converted.update(converted_override, override=True) else: msg = "Only able to append to lists and dicts" raise ValueError(msg) diff --git a/tests/config/test_main.py b/tests/config/test_main.py index 98752c63f..0e8728779 100644 --- a/tests/config/test_main.py +++ b/tests/config/test_main.py @@ -76,6 +76,12 @@ def test_config_override_appends_to_list(tox_ini_conf: ToxIniCreator) -> None: assert conf["passenv"] == ["foo", "bar"] +def test_config_override_appends_to_empty_list(tox_ini_conf: ToxIniCreator) -> None: + conf = tox_ini_conf("[testenv]", override=[Override("testenv.passenv+=bar")]).get_env("testenv") + conf.add_config("passenv", of_type=List[str], default=[], desc="desc") + assert conf["passenv"] == ["bar"] + + def test_config_override_appends_to_setenv(tox_ini_conf: ToxIniCreator) -> None: example = """ [testenv] @@ -87,6 +93,11 @@ def test_config_override_appends_to_setenv(tox_ini_conf: ToxIniCreator) -> None: assert conf["setenv"].load("baz") == "quux" +def test_config_override_appends_to_empty_setenv(tox_ini_conf: ToxIniCreator) -> None: + conf = tox_ini_conf("[testenv]", override=[Override("testenv.setenv+=foo=bar")]).get_env("testenv") + assert conf["setenv"].load("foo") == "bar" + + def test_config_override_cannot_append(tox_ini_conf: ToxIniCreator) -> None: example = """ [testenv]