From 646b20f389ad14578a604b55efaa932fff61dd6d Mon Sep 17 00:00:00 2001 From: Muneeb Sheikh Date: Sun, 11 Oct 2026 13:38:46 -0400 Subject: [PATCH] Allow same-key updates with duplicate conversion checks --- AUTHORS.rst | 2 ++ CHANGES.rst | 2 ++ box/box.py | 2 +- test/test_box.py | 22 ++++++++++++++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index 6b44851..c981509 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -5,6 +5,8 @@ reporting, all input is greatly appreciated! Code contributions: +- Muneeb Sheikh (muneikh) + - Alexandre Decan (AlexandreDecan) - dhilipsiva (dhilipsiva) - MAA (FooBarQuaxx) diff --git a/CHANGES.rst b/CHANGES.rst index c4a347d..b45db98 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,8 @@ Changelog Version 7.4.1 ------------- +* Allow reassigning an existing key when duplicate conversion checks are enabled. + * Fixing #303 Wrong version number (7.3.3) in 7.4.0 release (thanks to Michał Górny) Version 7.4.0 diff --git a/box/box.py b/box/box.py index 8252643..0f73078 100644 --- a/box/box.py +++ b/box/box.py @@ -957,7 +957,7 @@ def _conversion_checks(self, item): """ safe_item = self._safe_attr(item) - if safe_item in self._box_config["__safe_keys"]: + if safe_item in self._box_config["__safe_keys"] and self._box_config["__safe_keys"][safe_item] != item: dups = [f"{item}({safe_item})", f'{self._box_config["__safe_keys"][safe_item]}({safe_item})'] if self._box_config["box_duplicates"].startswith("warn"): warnings.warn(f"Duplicate conversion attributes exist: {dups}", BoxWarning) diff --git a/test/test_box.py b/test/test_box.py index e5c56e0..f278f3d 100644 --- a/test/test_box.py +++ b/test/test_box.py @@ -7,6 +7,7 @@ import pickle import platform import shutil +import warnings from multiprocessing import Queue from pathlib import Path from io import StringIO @@ -28,6 +29,7 @@ from ruamel.yaml import YAML from box import Box, BoxError, BoxKeyError, BoxList, ConfigBox, SBox, DDBox +from box.exceptions import BoxWarning from box.box import _get_dot_paths, _camel_killer, _recursive_tuples # type: ignore from box.converters import BOX_PARAMETERS @@ -630,6 +632,26 @@ def test_duplicate_errors(self): with pytest.raises(BoxError): my_box["^a"] = 3 + @pytest.mark.parametrize("policy", ["error", "warn"]) + @pytest.mark.parametrize("use_attribute", [False, True]) + def test_duplicate_checks_allow_reassigning_same_key(self, policy, use_attribute): + my_box = Box({"a b": 1}, box_duplicates=policy) + with warnings.catch_warnings(): + warnings.simplefilter("error", BoxWarning) + if use_attribute: + my_box.a_b = 2 + else: + my_box["a b"] = 2 + assert my_box.to_dict() == {"a b": 2} + assert my_box.a_b == 2 + if policy == "error": + with pytest.raises(BoxError): + my_box["a-b"] = 3 + assert my_box.to_dict() == {"a b": 2} + else: + with pytest.warns(BoxWarning): + my_box["a-b"] = 3 + def test_copy(self): my_box = Box(movie_data, camel_killer_box=True) bb = my_box.copy()