Skip to content

Commit

Permalink
Solves issue#59 - Treat None values as non-existing keys for default_…
Browse files Browse the repository at this point in the history
…box (#108)

* Solves issue#59 - Treat None values as non-existing keys for default_box
  • Loading branch information
haruntuncay authored and cdgriffith committed Oct 22, 2019
1 parent f02367d commit 145a10f
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 5 deletions.
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Code contributions:
- Brandon Gomes (bhgomes)
- Stretch (str3tch)
- (pwwang)
- Harun Tuncay (haruntuncay)

Suggestions and bug reporting:

Expand Down
13 changes: 9 additions & 4 deletions box/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ class Box(dict):
:param default_box: Similar to defaultdict, return a default value
:param default_box_attr: Specify the default replacement.
WARNING: If this is not the default 'Box', it will not be recursive
:param default_box_none_transform: When using default_box, treat keys with none values as absent. True by default
:param frozen_box: After creation, the box cannot be modified
:param camel_killer_box: Convert CamelCase to snake_case
:param conversion_box: Check for near matching keys as attributes
Expand All @@ -159,8 +160,8 @@ class Box(dict):

_protected_keys = dir({}) + ['to_dict', 'to_json', 'to_yaml', 'from_yaml', 'from_json', 'from_toml', 'to_toml']

def __new__(cls, *args: Any, box_it_up: bool = False, default_box: bool = False,
default_box_attr: Any = None, frozen_box: bool = False, camel_killer_box: bool = False,
def __new__(cls, *args: Any, box_it_up: bool = False, default_box: bool = False, default_box_attr: Any = None,
default_box_none_transform: bool = True, frozen_box: bool = False, camel_killer_box: bool = False,
conversion_box: bool = True, modify_tuples_box: bool = False, box_safe_prefix: str = 'x',
box_duplicates: str = 'ignore', box_intact_types: Union[Tuple, List] = (), **kwargs: Any):
"""
Expand All @@ -172,6 +173,7 @@ def __new__(cls, *args: Any, box_it_up: bool = False, default_box: bool = False,
obj._box_config.update({
'default_box': default_box,
'default_box_attr': default_box_attr or cls.__class__,
'default_box_none_transform': default_box_none_transform,
'conversion_box': conversion_box,
'box_safe_prefix': box_safe_prefix,
'frozen_box': frozen_box,
Expand All @@ -182,15 +184,16 @@ def __new__(cls, *args: Any, box_it_up: bool = False, default_box: bool = False,
})
return obj

def __init__(self, *args: Any, box_it_up: bool = False, default_box: bool = False,
default_box_attr: Any = None, frozen_box: bool = False, camel_killer_box: bool = False,
def __init__(self, *args: Any, box_it_up: bool = False, default_box: bool = False, default_box_attr: Any = None,
default_box_none_transform: bool = True, frozen_box: bool = False, camel_killer_box: bool = False,
conversion_box: bool = True, modify_tuples_box: bool = False, box_safe_prefix: str = 'x',
box_duplicates: str = 'ignore', box_intact_types: Union[Tuple, List] = (), **kwargs: Any):
super(Box, self).__init__()
self._box_config = _get_box_config(kwargs.pop('__box_heritage', None))
self._box_config.update({
'default_box': default_box,
'default_box_attr': default_box_attr or self.__class__,
'default_box_none_transform': default_box_none_transform,
'conversion_box': conversion_box,
'box_safe_prefix': box_safe_prefix,
'frozen_box': frozen_box,
Expand All @@ -208,6 +211,8 @@ def __init__(self, *args: Any, box_it_up: bool = False, default_box: bool = Fals
for k, v in args[0].items():
if v is args[0]:
v = self
if v is None and self._box_config['default_box'] and self._box_config['default_box_none_transform']:
continue
self[k] = v
elif isinstance(args[0], Iterable):
for k, v in args[0]:
Expand Down
3 changes: 2 additions & 1 deletion box/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

BOX_PARAMETERS = ('default_box', 'default_box_attr', 'conversion_box',
'frozen_box', 'camel_killer_box', 'box_it_up',
'box_safe_prefix', 'box_duplicates', 'ordered_box')
'box_safe_prefix', 'box_duplicates', 'ordered_box',
'default_box_none_transform')


def _exists(filename, create=False):
Expand Down
14 changes: 14 additions & 0 deletions test/test_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,20 @@ def test_default_box(self):
bx3 = Box(default_box=True, default_box_attr=3)
assert bx3.hello == 3

# Issue#59 https://github.com/cdgriffith/Box/issues/59 "Treat None values as non existing keys for default_box"
def test_default_box_none_transforms(self):
bx4 = Box({"noneValue": None, "inner": {"noneInner": None}}, default_box=True, default_box_attr="issue#59")
assert bx4.noneValue == "issue#59"
assert bx4.inner.noneInner == "issue#59"

bx5 = Box({"noneValue": None, "inner": {"noneInner": None}},
default_box=True,
default_box_none_transform=False,
default_box_attr="attr")
assert bx5.noneValue is None
assert bx5.absentKey == "attr"
assert bx5.inner.noneInner is None

def test_camel_killer_box(self):
td = extended_test_dict.copy()
td['CamelCase'] = 'Item'
Expand Down

0 comments on commit 145a10f

Please sign in to comment.