All public symbols are importable from json_database unless noted otherwise.
json_database/__init__.py:23
A dict subclass that persists its contents to a JSON file on disk.
JsonStorage(path: str, disable_lock: bool = False)| Parameter | Type | Default | Description |
|---|---|---|---|
path |
str |
required | Absolute or relative path to the JSON file. ~ is expanded. |
disable_lock |
bool |
False |
When True a no-op DummyLock is used instead of ComboLock. Disable only when you are certain there is no concurrent access. |
On construction the file is loaded immediately if it exists. If it does not exist the instance is an empty dict and no error is raised.
A .lock file is placed in the system temp directory, named after the basename
of path (e.g. /tmp/mydb.json.lock). combo_lock makes the lock safe across
threads and OS processes.
json_database/__init__.py:54
Clears the current dict and repopulates it from the file at path. Supports
commented JSON (lines starting with // or # are ignored). Silently skips
if the file does not exist.
json_database/__init__.py:80
Reloads from self.path. Raises DatabaseNotCommitted if the file does not
exist.
json_database/__init__.py:86
Serialises the dict to JSON and writes it to path (defaults to self.path).
Creates parent directories if they are missing. Writes with indent=4 and
ensure_ascii=False.
json_database/__init__.py:101
Deletes the file at self.path. No-op if the file does not exist.
json_database/__init__.py:106
Recursively merges conf into this dict. Returns self. See
merge_dict for parameter semantics.
__enter__ returns self. __exit__ calls store() and raises SessionError
if store() fails.
json_database/__init__.py:124
Extends JsonStorage. Data is encrypted with AES-256-GCM before being written
to disk and decrypted transparently on load. In memory the dict is always
plaintext.
Warning: Keys longer than 16 bytes are silently truncated to 16 bytes inside
encrypt_as_jsonanddecrypt_from_json(json_database/crypto.py:44). This happens after theAssertionErrorguard in the constructor, so passing a 32-byte key does not raise an error — only the first 16 bytes are used.
EncryptedJsonStorage(encrypt_key: str, path: str, disable_lock: bool = False)| Parameter | Type | Default | Description |
|---|---|---|---|
encrypt_key |
str |
required | Encryption key. Must be exactly 16 bytes (raises AssertionError otherwise). |
path |
str |
required | Path to the encrypted JSON file. |
disable_lock |
bool |
False |
Passed to JsonStorage. |
json_database/__init__.py:155
Calls the parent load_local, then decrypts the loaded payload in-place.
json_database/__init__.py:169
Encrypts the current plaintext dict, writes it, then restores the plaintext dict in memory. The file on disk always contains ciphertext.
json_database/__init__.py:182
A searchable list-of-records database backed by a JsonStorage. Records are
stored as a JSON array under a named key inside the file.
Note: Item IDs are stable list indices.
remove_itemtombstones the slot (None) rather than shifting subsequent IDs, so an ID obtained fromadd_itemorget_item_idremains valid for the lifetime of the database file. Tombstoned slots are invisible to iteration, search,__contains__, and__len__; accessing one raisesInvalidItemID.
JsonDatabase(name: str, path: str = None, disable_lock: bool = False, extension: str = "json")| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
required | Database name. Used as the key inside the JSON file and as the default filename stem. |
path |
str |
None |
File path. Defaults to {name}.{extension}. |
disable_lock |
bool |
False |
Passed to the underlying JsonStorage. |
extension |
str |
"json" |
File extension when path is not given. |
| Operation | Behaviour |
|---|---|
len(db) |
Count of live (non-tombstoned) records — json_database/__init__.py:239 |
db[item_id] |
Fetch live record by stable integer index; also accepts a string that can be cast to int; raises InvalidItemID for tombstoned slots — json_database/__init__.py:241 |
db[item_id] = value |
Replace record at index (calls update_item); raises InvalidItemID if index is out of range — json_database/__init__.py:256 |
item in db |
Exact equality check across all records (including tombstone slots, which are None and never equal a user item) |
iter(db) |
Yields only live (non-None) records in index order — json_database/__init__.py:262 |
repr(db) |
JSON-serialisable string of all live records |
json_database/__init__.py:290
Adds value to the database. Objects are serialised via jsonify_recursively
before storage. Returns the new length of the database.
If allow_duplicates=False (default) and an exact match already exists, returns
the existing item's ID instead of adding a duplicate.
json_database/__init__.py:357
Replaces the record at item_id with new_item.
json_database/__init__.py:362
Tombstones the slot at item_id by setting it to None. The slot is retained
so that all higher item IDs remain stable. Raises InvalidItemID if item_id
is out of range. The removed entry becomes invisible to __iter__, __len__,
search_by_key, search_by_value, and __contains__; accessing it via
db[item_id] raises InvalidItemID.
json_database/__init__.py:351
Returns the index of item using exact equality, or -1 if not found.
json_database/__init__.py:300
Returns a list of (item, index) tuples for all exact matches. match_strategy
is accepted but currently unused; only exact equality is implemented.
json_database/__init__.py:322
Finds the matching item and merges value into it using merge_dict. Raises
MatchError if no match is found and item_id is not provided. merge_strategy
is accepted but currently unused.
json_database/__init__.py:340
Finds the matching item and replaces it entirely with value. Raises MatchError
if no match and no item_id.
json_database/__init__.py:285
Unconditionally appends value (serialised). Returns the new length. Prefer
add_item for duplicate control.
json_database/__init__.py:272
Writes the database to disk via JsonStorage.store(). Must be called explicitly
when not using the context manager.
json_database/__init__.py:278
Discards in-memory changes by reloading from disk. Raises DatabaseNotCommitted
if the file does not exist.
json_database/__init__.py:281
Pretty-prints all records to stdout.
__enter__ returns self. __exit__ calls commit() and raises SessionError
on failure.
search_by_key(key: str, fuzzy: bool = False, thresh: float = 0.7, include_empty: bool = False) -> list
json_database/__init__.py:373
Iterates only live (non-tombstoned) records and returns those containing key.
- Exact mode: returns a list of dicts (the records that contain the key).
- Fuzzy mode: returns a list of
(record, score)tuples sorted by descending score.
json_database/__init__.py:384
Iterates only live (non-tombstoned) records and returns those where key == value.
- Exact mode: returns a list of matching records.
- Fuzzy mode: returns a list of
(record, score)tuples sorted by descending score.
All XDG classes resolve their storage path from environment variables at construction time. See XDG Paths for full details.
json_database/__init__.py:398
JsonStorageXDG(name: str, xdg_folder=xdg_cache_home(), disable_lock=False,
subfolder="json_database", extension="json")Stored at {xdg_folder}/{subfolder}/{name}.{extension}.
Default path: ~/.cache/json_database/{name}.json.
json_database/__init__.py:418
EncryptedJsonStorageXDG(encrypt_key: str, name: str, xdg_folder=xdg_data_home(),
disable_lock=False, subfolder="json_database", extension="ejson")Default path: ~/.local/share/json_database/{name}.ejson.
json_database/__init__.py:434
JsonDatabaseXDG(name: str, xdg_folder=xdg_data_home(), disable_lock=False,
subfolder="json_database", extension="jsondb")Default path: ~/.local/share/json_database/{name}.jsondb.
json_database/__init__.py:453
JsonConfigXDG(name: str, xdg_folder=xdg_config_home(), disable_lock=False,
subfolder="json_database", extension="json")Default path: ~/.config/json_database/{name}.json.
json_database/search.py:5
Fluent filter builder. Initialised from a JsonDatabase (or a single dict) and
narrowed by chaining filter methods. Each method mutates self.result and
returns self.
from json_database.search import Query
results = Query(db).equal("status", "active").above("score", 50).build()See Search and Query for all filter methods and their semantics.
json_database/exceptions.py
| Exception | Base | Raised when |
|---|---|---|
InvalidItemID |
ValueError |
item_id is out of range or invalid |
DatabaseNotCommitted |
FileNotFoundError |
reload() called before the file exists |
SessionError |
RuntimeError |
Context manager cannot commit/store |
MatchError |
ValueError |
merge_item or replace_item finds no match |
DecryptionKeyError |
KeyError |
Decryption fails (payload not raised by current code path) |
EncryptionKeyError |
KeyError |
Encryption fails (payload not raised by current code path) |
json_database/utils.py
These are used internally by the storage and search layers. They are importable but considered internal API.
json_database/utils.py:76
merge_dict(base: dict, delta: dict, merge_lists=True, skip_empty=True,
no_dupes=True, new_only=False) -> dictRecursively merges delta into base. Returns base.
| Parameter | Effect when True |
|---|---|
merge_lists |
Appends list items rather than replacing the list |
skip_empty |
Does not overwrite a non-empty base value with an empty delta value (except False) |
no_dupes |
Deduplicates when merging lists |
new_only |
Skips keys that already exist in base |
json_database/utils.py:38
fuzzy_match(x: str, against: str) -> floatReturns a similarity ratio in [0.0, 1.0] using difflib.SequenceMatcher.
json_database/utils.py:47
match_one(query: str, choices: list | dict) -> tuple[str, float]Returns (best_match, score) from choices using fuzzy_match.
json_database/utils.py:110
load_commented_json(filename: str) -> objectLoads a JSON file, stripping lines that start with // or #.
json_database/utils.py:321
jsonify_recursively(thing) -> dict | list | scalarConverts arbitrary Python objects to JSON-serialisable structures by calling
__dict__ on objects that are not already dicts, lists, or scalars.
json_database/utils.py:182, json_database/utils.py:215
Traverse nested dicts and lists to find all dicts that contain a given key.
The fuzzy variant returns (dict, score) tuples sorted by descending score.
json_database/utils.py:251, json_database/utils.py:283
Same traversal as above, but also checks that key == target_value. Fuzzy
variant matches on string similarity.
json_database/utils.py:5
A lock that does nothing. Used when disable_lock=True is passed to any
storage constructor. Implements the same interface as combo_lock.ComboLock
(acquire, release, __enter__, __exit__).