Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 7.3.1 #287

Merged
merged 3 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading