Skip to main content

Advanced Python dictionaries with dot notation access (fork with notify support)

Project description

BuildStatus License

Fork Notice

This is a fork of the original python-box library with enhanced notification capabilities.

New Features in This Fork:

  • Change Notifications: Box and BoxList objects support an on_change callback parameter that gets triggered whenever values are modified

  • Hierarchical Propagation: Changes in nested objects automatically propagate up to parent objects

  • Root Detection: The is_root parameter distinguishes between direct changes and propagated changes from nested objects

  • Modern Build System: Migrated to pyproject.toml and uv for dependency management while maintaining Cython optimization support

Notification System Usage:

from box import Box

def track_changes(obj, key, value, action, is_root):
    if is_root:
        print(f"Direct change: {key} = {value}")
    else:
        print(f"Nested change propagated: {key} changed")

# Create Box with change tracking
data = Box({
    'user': {'name': 'John', 'age': 30},
    'settings': ['theme', 'lang']
}, on_change=track_changes)

data.status = 'active'        # Triggers: Direct change: status = active
data.user.name = 'Jane'       # Triggers: Nested change propagated: user changed
data.settings.append('tz')    # Triggers: Nested change propagated: settings changed

For more details on the notification system, see the comprehensive test suite in test/test_notification.py.

Original Box Features

from box import Box

movie_box = Box({ "Robin Hood: Men in Tights": { "imdb stars": 6.7, "length": 104 } })

movie_box.Robin_Hood_Men_in_Tights.imdb_stars
# 6.7

Box will automatically make otherwise inaccessible keys safe to access as an attribute. You can always pass conversion_box=False to Box to disable that behavior. Also, all new dict and lists added to a Box or BoxList object are converted automatically.

There are over a half dozen ways to customize your Box and make it work for you.

Check out the new Box github wiki for more details and examples!

Install

Fork Installation

This fork is not published to PyPI. To use it, install directly from source:

# Clone this fork
git clone <your-fork-url>
cd Box

# Install with uv (recommended)
uv sync --all-extras
uv build  # Creates optimized wheel with Cython extensions

# Or install with pip in development mode
pip install -e .[all]

Build with Cython Optimization

This fork maintains full Cython optimization support:

# Install dependencies including Cython
uv sync --all-extras

# Build optimized wheel
uv build

# Install the built wheel
pip install dist/python_box-*.whl

Original Installation (upstream)

For the original python-box library without notification features:

pip install python-box[all]~=7.0 --upgrade

Install with selected dependencies

Box does not install external dependencies such as yaml and toml writers. Instead you can specify which you want, for example, [all] is shorthand for:

pip install python-box[ruamel.yaml,tomli_w,msgpack]~=7.0 --upgrade

But you can also sub out ruamel.yaml for PyYAML.

Check out more details on installation details.

Box 7 is tested on python 3.7+, if you are upgrading from previous versions, please look through any breaking changes and new features.

Optimized Version

Box has introduced Cython optimizations for major platforms by default. Loading large data sets can be up to 10x faster!

If you are not on a x86_64 supported system you will need to do some extra work to install the optimized version. There will be an warning of “WARNING: Cython not installed, could not optimize box” during install. You will need python development files, system compiler, and the python packages Cython and wheel.

Linux Example:

First make sure you have python development files installed (python3-dev or python3-devel in most repos). You will then need Cython and wheel installed and then install (or re-install with –force) python-box.

pip install Cython wheel
pip install python-box[all]~=7.0 --upgrade --force

If you have any issues please open a github issue with the error you are experiencing!

Overview

Box is designed to be a near transparent drop in replacements for dictionaries that add dot notation access and other powerful feature.

There are a lot of types of boxes to customize it for your needs, as well as handy converters!

Keep in mind any sub dictionaries or ones set after initiation will be automatically converted to a Box object, and lists will be converted to BoxList, all other objects stay intact.

Check out the Quick Start for more in depth details.

Notification System (Fork Feature)

This fork adds a comprehensive change notification system to Box and BoxList objects.

Basic Usage

Pass an on_change callback when creating a Box or BoxList:

def my_callback(obj, key, value, action, is_root):
    print(f"Change: {key} = {value} (action: {action}, is_root: {is_root})")

data = Box({'user': {'name': 'John'}}, on_change=my_callback)
data.user.name = 'Jane'  # Triggers callback

Callback Parameters

  • obj: The object where the callback was originally set (always the root)

  • key: The key/index that changed

  • value: The new value (or None for deletions)

  • action: Type of change ('set', 'delete', 'clear', 'append', 'insert', 'child_change')

  • is_root: True for direct changes, False for nested changes that propagated up

Change Types

  • Direct changes: is_root=True - modifications made directly to the root object

  • Propagated changes: is_root=False - modifications made to nested objects that bubble up

Supported Operations

All modification operations trigger notifications:

data = Box({}, on_change=callback)

# Set operations
data.key = 'value'              # action='set', is_root=True
data['key'] = 'value'           # action='set', is_root=True
data.update({'a': 1, 'b': 2})   # action='set', is_root=True (per key)

# Delete operations
del data.key                    # action='delete', is_root=True
data.pop('key')                 # action='delete', is_root=True
data.clear()                    # action='clear', is_root=True

# Nested changes
data.nested.value = 42          # action='child_change', is_root=False

BoxList Support

BoxList objects also support notifications:

items = BoxList([1, 2, 3], on_change=callback)

items.append(4)                 # action='append', is_root=True
items.insert(0, 0)              # action='insert', is_root=True
items[1] = 'new'                # action='set', is_root=True
items.pop()                     # action='pop', is_root=True
items.remove('new')             # action='remove', is_root=True
items.clear()                   # action='clear', is_root=True

Error Handling

Callback errors are silently caught to prevent disrupting normal operations:

def bad_callback(obj, key, value, action, is_root):
    raise Exception("Callback error!")

data = Box(on_change=bad_callback)
data.key = 'value'  # Works normally, error is ignored

Use Cases

  • Change tracking: Monitor all modifications to complex data structures

  • Validation: Implement custom validation logic on data changes

  • Persistence: Automatically save data when changes occur

  • Debugging: Log all changes for debugging purposes

  • Event systems: Trigger events based on data modifications

Performance Notes

  • Cython optimization is fully supported for notification-enabled objects

  • Callback overhead is minimal when no callback is set

  • Parent references are efficiently managed automatically

Box can be instantiated the same ways as dict.

Box({'data': 2, 'count': 5})
Box(data=2, count=5)
Box({'data': 2, 'count': 1}, count=5)
Box([('data', 2), ('count', 5)])

# All will create
# <Box: {'data': 2, 'count': 5}>

Box is a subclass of dict which overrides some base functionality to make sure everything stored in the dict can be accessed as an attribute or key value.

small_box = Box({'data': 2, 'count': 5})
small_box.data == small_box['data'] == getattr(small_box, 'data')

All dicts (and lists) added to a Box will be converted on insertion to a Box (or BoxList), allowing for recursive dot notation access.

Box also includes helper functions to transform it back into a dict, as well as into JSON, YAML, TOML, or msgpack strings or files.

Thanks

A huge thank you to everyone that has given features and feedback over the years to Box! Check out everyone that has contributed.

A big thanks to Python Software Foundation, and PSF-Trademarks Committee, for official approval to use the Python logo on the Box logo!

Also special shout-out to PythonBytes, who featured Box on their podcast.

License

MIT License, Copyright (c) 2017-2023 Chris Griffith. See LICENSE file.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_box_notify-1.0.3.tar.gz (57.7 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

python_box_notify-1.0.3-cp313-cp313-win_amd64.whl (463.3 kB view details)

Uploaded CPython 3.13Windows x86-64

python_box_notify-1.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

python_box_notify-1.0.3-cp313-cp313-macosx_10_13_universal2.whl (1.0 MB view details)

Uploaded CPython 3.13macOS 10.13+ universal2 (ARM64, x86-64)

python_box_notify-1.0.3-cp312-cp312-win_amd64.whl (463.3 kB view details)

Uploaded CPython 3.12Windows x86-64

python_box_notify-1.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

python_box_notify-1.0.3-cp312-cp312-macosx_10_13_universal2.whl (1.0 MB view details)

Uploaded CPython 3.12macOS 10.13+ universal2 (ARM64, x86-64)

python_box_notify-1.0.3-cp311-cp311-win_amd64.whl (487.9 kB view details)

Uploaded CPython 3.11Windows x86-64

python_box_notify-1.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

python_box_notify-1.0.3-cp311-cp311-macosx_10_9_universal2.whl (1.1 MB view details)

Uploaded CPython 3.11macOS 10.9+ universal2 (ARM64, x86-64)

python_box_notify-1.0.3-cp310-cp310-win_amd64.whl (484.4 kB view details)

Uploaded CPython 3.10Windows x86-64

python_box_notify-1.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.4 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

python_box_notify-1.0.3-cp310-cp310-macosx_10_9_universal2.whl (1.0 MB view details)

Uploaded CPython 3.10macOS 10.9+ universal2 (ARM64, x86-64)

python_box_notify-1.0.3-cp39-cp39-win_amd64.whl (485.1 kB view details)

Uploaded CPython 3.9Windows x86-64

python_box_notify-1.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.4 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

python_box_notify-1.0.3-cp39-cp39-macosx_10_9_universal2.whl (1.0 MB view details)

Uploaded CPython 3.9macOS 10.9+ universal2 (ARM64, x86-64)

File details

Details for the file python_box_notify-1.0.3.tar.gz.

File metadata

  • Download URL: python_box_notify-1.0.3.tar.gz
  • Upload date:
  • Size: 57.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for python_box_notify-1.0.3.tar.gz
Algorithm Hash digest
SHA256 2c3d7f50143d8fa298767fe00f70cbc7c753f08d3c00753bcc6eabd0425f4713
MD5 740fab56683d30661062570114ae9263
BLAKE2b-256 2410b826e102934f6b25a061958d8211dbef571de861d468d9a712151711476e

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp313-cp313-win_amd64.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 d2ab313d7dd835acf1f00b959f7d3cdaec4fffa9ecc2074cf98d94f5135d9eed
MD5 dae66cb8e3324314837344d795f0132a
BLAKE2b-256 1ec2a7ff1b27f3d0b84bfe75daaf21c2b647ed178530250af74630b26178c8e6

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 882af3e208466f41b02a9303efd9517e8e1acb483c66bcae4711e08fdae84d03
MD5 a50e976095bd455ca277484f72478b78
BLAKE2b-256 f11a0db87148ee044f4d47eec51e130da105fe7c0f7cfaf8e714b9257785e847

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp313-cp313-macosx_10_13_universal2.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp313-cp313-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 645574e68c0cd42522b2a394d3b27d37c7975a8b4a4141efe221e10c7c6f38f5
MD5 6604711f01f6c98b053091ff93fe494f
BLAKE2b-256 bb6b2615d8800372d44399b7349cef7c56270cce8ceac942caa17a51f1816e5d

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 d63ef0d4014af653ed5c9e8e5015de04638ac9c04f89387877be293a70c3bec9
MD5 e2838ab2959a5d3f16a90922db210e35
BLAKE2b-256 3626046f50239d5ba564314558cdcfe4d5a721f407a0f668c8824b3d6180a8ff

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 da7437b631465068a9e9e21344ec73d6a5c1e999dc44caa98e23ec3abc1c98c0
MD5 3f13928aabaf5d9b4027e0c7c6f06dec
BLAKE2b-256 23f070904493f52b6fd2760e56b8158c77d8221e1dd4798624ff5457cc29fbdd

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp312-cp312-macosx_10_13_universal2.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp312-cp312-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 4a60b2c842c2180863d4ab6fe718b332aefa15b1bbef92c0733f2fabdb872093
MD5 e6b2b7875918649ec92954968d5eb0fc
BLAKE2b-256 34be8e3645330a219b0c7e096ede83c41a971122df46bcb5de1000f9e2870c8d

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 4339afaeeafef15197f2b132c5912d618be050242bf7b04fd9b973aae696dda3
MD5 4a19682108a8208164fa45691c572260
BLAKE2b-256 39bcc576dd6bbb936fd89d2be845961da9ad739aad6a9a2c4fc347e538ed142f

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 7dca2a508316ac67901f8d8a81652e6fca86708ff5821a09e51dd295086e4c14
MD5 d114921d222b18565930f247eaa1cf3b
BLAKE2b-256 f62a202a398b45e5e29ea351e88c71133212a019a51a47920a091df861a965cb

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp311-cp311-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp311-cp311-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 8af99b71626227aa00bec19d92d2b1ef2bc6b94187b1c65c8d3aba0034534705
MD5 a4e382ee62b090b5322e9bc75bf47f2b
BLAKE2b-256 f2304a482797c2745fc9cdede1281534ee8b61f6ddd563b2a712c59dd6714a5b

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 5ed3bc0c430c8ec080dc9f8b415264aa3638129ae02bc7384a0a414cda1b4c82
MD5 c36395d30199f1614bd8d571d1af65e9
BLAKE2b-256 4a287379c2a38413f78777225b4e930ce439248662ac47d914d4bdcf8852fe79

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 bcb3623db2eef55de7effd22c4464d8c6c6a7a9a375350cfb4f1f5cf9d50e733
MD5 1e314e62b1c9c0ee6865de9b2f13e7d9
BLAKE2b-256 bbb671b0c0fd92a898b74ba1299605dcb2f651091cf8ade24d6bcef563633152

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp310-cp310-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp310-cp310-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 b86c8e6db5fe5df73c7e96c1a979e597761d4f729e11d7f8cc8d27b040675496
MD5 ce6a972aa72e5b2c22dc96581b17c29c
BLAKE2b-256 98da55c00304bc66c08a5e4f05b03c0970e2faac77ee2687ea30c661bc475c33

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp39-cp39-win_amd64.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 7668a10479b59877e1208de49c89ed6217b20a90e8e0bfcd89d4254718a790f2
MD5 6c41a5a57ff0ef424705d1cb75e938a5
BLAKE2b-256 9facaedd8759aeb1e1ffd8f732dbb066de91dba252e79593c77f450490fbe48c

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 654601df37f60b8659866b4693442ce650372f5260a5e33aea0f62eefd761611
MD5 22c67b5d30b31375be163469a32313d5
BLAKE2b-256 4a2d14ca0072c6fd7bc2a54c614135967b6fe309babc4c0cb069f21c5ebd4c76

See more details on using hashes here.

File details

Details for the file python_box_notify-1.0.3-cp39-cp39-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for python_box_notify-1.0.3-cp39-cp39-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 09049092d49768ed909119db69f8cd801901dff70cd5adf725e2508458e94db6
MD5 ae823ebaae3ab21125316fbd0a4d1d93
BLAKE2b-256 8e180d31739ebac250acb811c451d162a98bd19292f12b922acd131579b4d8f6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page