From c9ca1b2856e49e5a1161b46710476b2fbd9b97b9 Mon Sep 17 00:00:00 2001 From: santhreal <64453045+santhreal@users.noreply.github.com> Date: Fri, 17 Jul 2026 23:44:06 -0700 Subject: [PATCH] Fix IndexError on trailing dotted keys with default_box box_dots paths that end with a trailing dot leave an empty children segment; children[0] then raised IndexError while creating the intermediate container. Use children[:1] so empty children create a Box and set the empty-string key, matching existing parent paths. --- box/box.py | 3 ++- box/box_list.py | 3 ++- test/test_box.py | 11 +++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/box/box.py b/box/box.py index 8252643..105be19 100644 --- a/box/box.py +++ b/box/box.py @@ -669,7 +669,8 @@ def __setitem__(self, key, value): if hasattr(self[first_item], "__setitem__"): return self[first_item].__setitem__(children, value) elif self._box_config["default_box"]: - if children[0] == "[": + # children may be "" for trailing dots (e.g. "a."); treat as Box + empty key. + if children[:1] == "[": super().__setitem__(first_item, box.BoxList(**self.__box_config(extra_namespace=first_item))) else: super().__setitem__( diff --git a/box/box_list.py b/box/box_list.py index 72609ff..adc4ed4 100644 --- a/box/box_list.py +++ b/box/box_list.py @@ -106,7 +106,8 @@ def __setitem__(self, key, value): return super().__setitem__(pos, value) children = key[len(list_pos.group()) :].lstrip(".") if self.box_options.get("default_box"): - if children[0] == "[": + # children may be "" after a trailing dot on a list path (e.g. "[0]."). + if children[:1] == "[": super().__setitem__(pos, box.BoxList(**self.box_options)) else: super().__setitem__(pos, self.box_options.get("box_class")(**self.box_options)) diff --git a/test/test_box.py b/test/test_box.py index e5c56e0..685aa74 100644 --- a/test/test_box.py +++ b/test/test_box.py @@ -344,6 +344,17 @@ def test_set_default_box_dots(self): assert t == Box(a=1, b=[1, 2]) assert t.setdefault("c", [{"d": 2}]) == BoxList([{"d": 2}]) + def test_box_dots_trailing_dot_default_box(self): + # Trailing dots leave an empty children segment; must set empty-string key, not IndexError. + b = Box(default_box=True, box_dots=True) + b["a."] = 1 + assert b["a"][""] == 1 + b2 = Box(default_box=True, box_dots=True) + b2["a[0]."] = 2 + assert b2.a[0][""] == 2 + b3 = Box(default_box=True, box_dots=True) + assert isinstance(b3[".."], Box) + def test_from_json_file(self): bx = Box.from_json(filename=data_json_file) assert isinstance(bx, Box)