Skip to main content

A dict subclass that automatically persists every mutation to a JSON file

Project description

json-backed-dict

A dict subclass that automatically persists every mutation to a JSON file.

from json_backed_dict import JsonBackedDict as JBD

d = JBD('config.json')
d['host'] = 'localhost'   # written to disk immediately
d['port'] = 5432          # written to disk immediately

Features

  • Automatic persistence — every __setitem__, __delitem__, update, pop, etc. atomically writes the file
  • Nested mutation tracking — mutating a nested dict or list is also persisted
  • Temporal type round-trippingdatetime, date, time, and timedelta values survive save/load cycles as their Python types
  • Atomic writes — uses a temp file + os.replace so a crash mid-write never corrupts the file
  • Fast — backed by orjson for serialization

Installation

pip install json-backed-dict

Requires Python 3.9+.

Usage

Basic operations

from json_backed_dict import JsonBackedDict as JBD

d = JBD('data.json')

d['name'] = 'Alice'
d['scores'] = [10, 20, 30]
d.update({'active': True, 'level': 5})

print(d['name'])      # 'Alice'
print(d.get('age'))   # None
del d['level']

All standard dict methods work: keys(), values(), items(), pop(), setdefault(), popitem(), clear(), update().

Loading an existing file

If the file already exists, it is loaded on construction. The initial argument is ignored when a file is present.

d = JBD('data.json')          # loads existing file
d = JBD('data.json', initial={'x': 1})  # initial ignored, file loaded

Seeding a new file

d = JBD('settings.json', initial={'debug': False, 'timeout': 30})

initial is only used when creating a new file.

Nested mutations

Nested dicts and lists returned by __getitem__ and get() are proxy objects. Mutating them persists the change to the root file automatically.

d = JBD('data.json', initial={'config': {'timeout': 10}, 'tags': ['a', 'b']})

d['config']['timeout'] = 30   # persisted
d['tags'].append('c')         # persisted
d['config'].update({'retries': 3})  # persisted

Temporal types

datetime, date, time, and timedelta values are serialized to strings and deserialized back to their Python types on load. No manual conversion needed.

from datetime import datetime, date, time, timedelta

d = JBD('data.json')
d['created_at'] = datetime(2024, 6, 15, 10, 30, 45)
d['due_date']   = date(2024, 7, 1)
d['start_time'] = time(9, 0)
d['ttl']        = timedelta(hours=24)

d2 = JBD('data.json')
isinstance(d2['created_at'], datetime)   # True
isinstance(d2['ttl'], timedelta)         # True

Note: This means strings that look like dates, times, or timedeltas cannot be stored as plain strings — they will be coerced to the corresponding Python type on the next load. For example, storing "2024-01-15" will be read back as date(2024, 1, 15).

Supported value types

Type Example
str 'hello'
int 42
float 3.14
bool True
None None
list [1, 2, 3]
dict {'key': 'value'}
datetime datetime(2024, 1, 1, 12, 0)
date date(2024, 1, 1)
time time(12, 0, 0)
timedelta timedelta(days=1, hours=2)

All dict keys must be str. Attempting to store any other type raises TypeError before any mutation occurs.

Limitations

Thread-safe, but not process-safe. Methods implemented by JsonBackedDict acquire an instance-level lock for their full duration, making individual operations on a single instance atomic. Concurrent writes from multiple processes can still interleave: each write creates a temp file and calls os.replace, so the last writer wins and earlier changes are silently lost.

Not an IPC mechanism. If another process modifies the backing file, the current instance will never see those changes. To pick up external changes, construct a new JBD from the same path.

License

MIT

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

json_backed_dict-1.0.1.tar.gz (86.5 kB view details)

Uploaded Source

Built Distribution

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

json_backed_dict-1.0.1-py3-none-any.whl (8.8 kB view details)

Uploaded Python 3

File details

Details for the file json_backed_dict-1.0.1.tar.gz.

File metadata

  • Download URL: json_backed_dict-1.0.1.tar.gz
  • Upload date:
  • Size: 86.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for json_backed_dict-1.0.1.tar.gz
Algorithm Hash digest
SHA256 3ddf4f0b9e5cc21f55df930e838d8b40224ba5331c8d297b92c0cd9353cc148a
MD5 a2c01728e9485a63a2cceb95d1580071
BLAKE2b-256 45c6a604fae2b7b11bfc9c2f22f0ebc7d21c457149f32fa6988a0df2b54c94ee

See more details on using hashes here.

Provenance

The following attestation bundles were made for json_backed_dict-1.0.1.tar.gz:

Publisher: publish.yml on skullydazed/json-backed-dict

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file json_backed_dict-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for json_backed_dict-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9186603ccdd904f5e3704ba15cd0a78c37f3f7be7a44a483969f65ee3a4157c4
MD5 a8d8656eaec673887db404b9a32eb384
BLAKE2b-256 7f1cedcd6c4800df7fa589f4cc619f02f60c6bf0e7948dc7092e921706221abe

See more details on using hashes here.

Provenance

The following attestation bundles were made for json_backed_dict-1.0.1-py3-none-any.whl:

Publisher: publish.yml on skullydazed/json-backed-dict

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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