Skip to content

Major Version Breaking Changes

Chris Griffith edited this page Jun 15, 2023 · 5 revisions

Box 7.1

Removed support for lists that had circular references of themselves

Due to https://github.com/cdgriffith/Box/issues/251

Box 7

box dots now treats any key with . in it as if it should be split

That means if you provide my_box['a.b.c'] = 3 to a new default box, it will split it down into sub boxes!

my_box = Box(box_dots=True, default_box=True)
my_box['a.b.c']
# Box({'a': {'b': {'c': {}}}})

However this now means trying to set it without default_box also true will result in an error:

my_box = Box(box_dots=True)
my_box['a.b.c'] = 3 

# box.exceptions.BoxKeyError: ''Box' object has no attribute a'

tomli and tomli_w are installed by default with all setup extra instead of toml

pip install python-box[all] is now equivlenet to pip install python-box["ruamel.yaml>=0.17", "tomli; python_version < '3.11'", "tomli-w", "msgpack"]

Right side union (|) and additions (+) now update in order of operation

Now:

my_box = Box(a=1, b=2) 

{'a': 5} | my_box == Box(a=1, b=2) 

Previously:

my_box = Box(a=1, b=2) 

{'a': 5} | my_box == Box(a=5, b=2) 

New box_namespace keyword argument

If you were using the key box_namespace before it must be changed as it will no longer work

New protected method getdoc

Doing Box().getdoc() or Box()? in iPython will return the Box docstring

Box 6

UTF-8 supported attributes

Box 6 comes with extended UTF-8 support for anything that is valid python. Which means in previous cases where characters outside the ascii latin alphabet were removed. Now they will be there.

my_box = Box({"σeq": 1}) 

# 6.0 behavior
my_box.σeq

#5.x and lower - will remove the σ
my_box.eq   

ruamel.yaml updates

Box 6 removed support for older ruamel.yaml versions, and requires 0.17 at minimum. It also uses the Round Trip loader for ruamel.yaml by default.

This means if you get the error ruamel.yaml.representer.RepresenterError: cannot represent an object you need to either fix your code (as you should probably not be dumping python objects) or use .to_yaml(ruamel_typ='unsafe') in your code.

Cython optimizations

Box 6 is also now using Cython for speed ups on supported platforms. If you have any weird errors and need an easier to debug version, grab the *-any.whl file and manually install https://pypi.org/project/python-box/#files

Box 5

Box 5.0 no longer installs all possible converter libraries, nor requires them for use (unless you are trying to run that missing transform.) To install them when box is installed, you can include them as extra requirements via pip install -r requirements.txt.

pip install --upgrade python-box[ruamel.yaml,toml,msgpack]

You can install all, none, or just the one(s) you need. The options are:

  • ruamel.yaml
  • PyYAML (if ruamel.yaml is also detected, Box will use ruamel.yaml first)
  • toml
  • msgpack

Box 4

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)

pip install --upgrade python-box>=4

If your application is no longer working, and need a quick fix:

pip install --upgrade python-box<4

Additions

Dot notation access by keys!

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]']

Support for adding two Boxes together

from box import Box
Box(a=4) + Box(a='overwritten', b=5)
# <Box: {'a': 'overwritten', 'b': 5}>

Additional additions

  • Added toml conversion support
  • Added CSV conversion support
  • Added box_from_file helper function

Changes

Adding merge_update as its own function, update now works like the default dictionary update

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}}>"

Camel Killer Box now changes keys on insertion

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'}

Conversion keys are now a bit smarter with how they are handled

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'}>

YAML 1.2 default instead of 1.1

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 <https://yaml.readthedocs.io/en/latest/pyyaml.html#differences-with-pyyaml>_

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

Additional changes

  • Default Box will also work on None placeholders

Removed

No more Python 2 support

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.

Removing Ordered Box

As dictionaries are ordered by default in Python 3.6+ there is no point to continue writing and testing code outside of that.

Removing BoxObject

As BoxObject was not cross platform compatible and had some issues <https://github.com/GrahamDumpleton/wrapt/issues/132>_ it has been removed.

Removing box_it_up

Everything is converted on creation again, as the speed was seldom worth the extra headaches associated with such a design.

Clone this wiki locally