Skip to content

Commit

Permalink
Version 7.3.1 (#287)
Browse files Browse the repository at this point in the history
* Fixing #275 default_box_create_on_get is ignored with from_yaml (thanks to Ward Loos)
* Fixing #285 Infinite Recursion when accessing non existent list index in a DefaultBox with box_dots (thanks to Jesper Schlegel)

---------

Co-authored-by: jesperschlegel <jesperhschlegel@gmail.com>
Co-authored-by: Jesper Schlegel <jesper.schlegel@link2.ai>
  • Loading branch information
3 people authored Jan 15, 2025
1 parent 37b9181 commit 91cc956
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 13 deletions.
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Code contributions:
- Muspi Merol (CNSeniorious000)
- YISH (mokeyish)
- Bit0r
- Jesper Schlegel (jesperschlegel)


Suggestions and bug reporting:
Expand Down
7 changes: 7 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Changelog
=========

Version 7.3.1
-------------

* Fixing #275 default_box_create_on_get is ignored with from_yaml (thanks to Ward Loos)
* Fixing #285 Infinite Recursion when accessing non existent list index in a DefaultBox with box_dots (thanks to Jesper Schlegel)


Version 7.3.0
-------------

Expand Down
2 changes: 1 addition & 1 deletion box/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-

__author__ = "Chris Griffith"
__version__ = "7.3.0"
__version__ = "7.3.1"

from box.box import Box
from box.box_list import BoxList
Expand Down
14 changes: 9 additions & 5 deletions box/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ def _parse_box_dots(bx, item, setting=False):
if char == "[":
return item[:idx], item[idx:]
elif char == ".":
if item[:idx] in bx:
return item[:idx], item[idx + 1 :]
return item[:idx], item[idx + 1 :]
if setting and "." in item:
return item.split(".", 1)
raise BoxError("Could not split box dots properly")
Expand Down Expand Up @@ -657,9 +656,14 @@ def __setitem__(self, key, value):
if hasattr(self[first_item], "__setitem__"):
return self[first_item].__setitem__(children, value)
elif self._box_config["default_box"]:
super().__setitem__(
first_item, self._box_config["box_class"](**self.__box_config(extra_namespace=first_item))
)
if children[0] == "[":
super().__setitem__(
first_item, box.BoxList(**self.__box_config(extra_namespace=first_item))
)
else:
super().__setitem__(
first_item, self._box_config["box_class"](**self.__box_config(extra_namespace=first_item))
)
return self[first_item].__setitem__(children, value)
else:
raise BoxKeyError(f"'{self.__class__}' object has no attribute {first_item}")
Expand Down
10 changes: 9 additions & 1 deletion box/box_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,17 @@ def __setitem__(self, key, value):
if self.box_options.get("box_dots") and isinstance(key, str) and key.startswith("["):
list_pos = _list_pos_re.search(key)
pos = int(list_pos.groups()[0])
if pos >= len(self) and self.box_options.get("default_box"):
self.extend([None] * (pos - len(self) + 1))
if len(list_pos.group()) == len(key):
return super().__setitem__(pos, value)
return super().__getitem__(pos).__setitem__(key[len(list_pos.group()) :].lstrip("."), value)
children = key[len(list_pos.group()):].lstrip(".")
if self.box_options.get("default_box"):
if children[0] == "[":
super().__setitem__(pos, box.BoxList(**self.box_options))
else:
super().__setitem__(pos, self.box_options.get("box_class")(**self.box_options))
return super().__getitem__(pos).__setitem__(children, value)
super().__setitem__(key, value)

def _is_intact_type(self, obj):
Expand Down
11 changes: 7 additions & 4 deletions box/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,19 @@ class BoxTomlDecodeError(BoxError, tomli.TOMLDecodeError): # type: ignore
BOX_PARAMETERS = (
"default_box",
"default_box_attr",
"conversion_box",
"default_box_none_transform",
"default_box_create_on_get",
"frozen_box",
"camel_killer_box",
"conversion_box",
"modify_tuples_box",
"box_safe_prefix",
"box_duplicates",
"default_box_none_transform",
"box_dots",
"modify_tuples_box",
"box_intact_types",
"box_dots",
"box_recast",
"box_class",
"box_namespace",
)


Expand Down
4 changes: 2 additions & 2 deletions test/test_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -1340,8 +1340,8 @@ def test_box_kwargs_should_not_be_included(self):
bx = Box(**params)
assert bx == Box()

for param in BOX_PARAMETERS:
assert param in params
for param in params:
assert param in BOX_PARAMETERS

def test_box_greek(self):
# WARNING μ is ord 956 whereas µ is ord 181 and will not work due to python NFKC normalization
Expand Down
19 changes: 19 additions & 0 deletions test/test_box_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,25 @@ def test_box_list_dots(self):
for key in keys:
db[key]

def test_box_list_default_dots(self):
box_1 = Box(default_box=True, box_dots=True)
box_1["a[0]"] = 42
assert box_1.a[0] == 42

box_1["b[0].c[0].d"] = 42
assert box_1.b[0].c[0].d == 42

box_1["c[0][0][0]"] = 42
assert box_1.c[0][0][0] == 42

box_2 = Box(default_box=True, box_dots=True)
box_2["a[4]"] = 42
assert box_2.a.to_list() == [None, None, None, None, 42]

box_3 = Box(default_box=True, box_dots=True)
box_3["a.b[0]"] = 42
assert box_3.a.b[0] == 42

def test_box_config_propagate(self):
structure = Box(a=[Box(default_box=False)], default_box=True, box_inherent_settings=True)
assert structure._box_config["default_box"] is True
Expand Down

0 comments on commit 91cc956

Please sign in to comment.