Box 4.0 has brought a lot of great new features, but also some breaking changes. They are documented here to help you upgrade.
To install the latest 4.x you will need at least Python 3.6 (or current supported python 3.x version)
..code:: bash
pip install --upgrade python-box>=4
If your application is no longer working, and need a quick fix:
..code:: bash
pip install --upgrade python-box<4
Enabled with box_dots=True.
from box import Box
my_box = Box(a={'b': {'c': {'d': 'my_value'}}}, box_dots=True)
print(my_box['a.b.c.d'])
# 'my_value'
my_box['a.b.c.d'] = 'test'
# <Box: {'a': {'b': {'c': {'d': 'test'}}}}>
del my_box['a.b.c.d']
# <Box: {'a': {'b': {'c': {}}}}>This only works with keys that are string to begin with, as we don't do any automatic conversion behind the scene.
4.1 Update: This now also supports list traversal, like my_box['my_key[0][0]']
from box import Box
Box(a=4) + Box(a='overwritten', b=5)
# <Box: {'a': 'overwritten', 'b': 5}>- Added toml conversion support
- Added CSV conversion support
- Added box_from_file helper function
Traditional update is destructive to nested dictionaries.
from box import Box
box_one = Box(inside_dict={'data': 5})
box_two = Box(inside_dict={'folly': True})
box_one.update(box_two)
repr(box_one)
# <Box: {'inside_dict': {'folly': True}}>Merge update takes existing sub dictionaries into consideration
from box import Box
box_one = Box(inside_dict={'data': 5})
box_two = Box(inside_dict={'folly': True})
box_one.merge_update(box_two)
repr(box_one)
"<Box: {'inside_dict': {'data': 5, 'folly': True}}>"There was a bug in the 4.0 code that meant camel killer was not working at all under normal conditions due to the change of how the box is instantiated.
from box import Box
my_box = Box({'CamelCase': 'Item'}, camel_killer_box=True)
assert my_box.camel_case == 'Item'
print(my_box.to_dict())
# {'camel_case': 'Item'}Keys with safety underscores used to be treated internally as if the underscores didn't always exist, i.e.
from box import Box
b = Box(_out = 'preserved')
b.update({'out': 'updated'})
# expected:
# {'_out': 'preserved', 'out': 'updated'}
# observed:
# {'_out': 'updated'}Those issues have been (hopefully) overcome and now will have the expected <Box: {'_out': 'preserved', 'out': 'updated'}>
ruamel.yaml is now an install requirement and new default instead of PyYAML. By design ruamel.yaml uses the newer YAML v1.2 (which PyYAML does not yet support as of Jan 2020).
To use the older version of 1.1, make sure to specify the version while using the from_yaml methods.
from box import Box
Box.from_yaml("fire_ze_missiles: no")
<Box: {'fire_ze_missiles': 'no'}>
Box.from_yaml("fire_ze_missiles: no", version='1.1')
<Box: {'fire_ze_missiles': False}>You can read more about the differences here
To use PyYAML instead of ruamel.yaml you must install box without dependencies (such as --no-deps with pip)
If you do chose to stick with PyYaML, you can suppress the warning on just box's import:
import warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore")
from box import Box- Default Box will also work on None placeholders
Python 2 is soon officially EOL and Box 4 won't support it in anyway. Box 3 will not be updated, other than will consider PRs for bugs or security issues.
As dictionaries are ordered by default in Python 3.6+ there is no point to continue writing and testing code outside of that.
As BoxObject was not cross platform compatible and had some issues it has been removed.
Everything is converted on creation again, as the speed was seldom worth the extra headaches associated with such a design.