Database

The database is represented by a ParamDB object. A path is passed, and a new database file is created if it does not already exist. We can parameterize the class with the root data type in order for its methods (e.g. ParamDB.commit()) work properly with type checking. For example:

from paramdb import ParamDataclass, ParamDB

class Root(ParamDataclass):
    param: CustomParam

class CustomParam(ParamDataclass):
    value: float

param_db = ParamDB[Root]("path/to/param.db")

Important

The ParamDB object should be created once per project and imported by other files that access the database.

Note

Dataclass fields created with init=False will not be stored in or restored from the database. See dataclasses.field for more information.

Commit and Load

Data can be committed using ParamDB.commit() and loaded using ParamDB.load(), which either loads the most recent commit, or takes a specific commit ID. Note that commit IDs start from 1. For example:

root = Root(param=CustomParam(value=1.23))
param_db.commit(f"Initial commit", root)
for _ in range(10):
    root.param.value += 1
    param_db.commit(f"Increment param value to {root.param.value}", root)

We can then load the most recent commit:

param_db.load()
Root(param=CustomParam(value=11.23))

Or a specific previous commit:

param_db.load(5)
Root(param=CustomParam(value=5.23))

Commit History

We can get a list of commits (as CommitEntry objects) using the ParamDB.commit_history() method.

param_db.commit_history()
[CommitEntry(id=1, message='Initial commit', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 194949, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=2, message='Increment param value to 2.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 201329, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=3, message='Increment param value to 3.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 205576, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=4, message='Increment param value to 4.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 210051, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=5, message='Increment param value to 5.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 214435, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=6, message='Increment param value to 6.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 219002, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=7, message='Increment param value to 7.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 223596, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=8, message='Increment param value to 8.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 227842, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=9, message='Increment param value to 9.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 231916, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=10, message='Increment param value to 10.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 235603, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=11, message='Increment param value to 11.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 239600, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC')))]

A specific range can also be requested by passing in start and/or end indices to ParamDB.commit_history(), which function like Python list slicing, where the start index is inclusive and the end is exclusive. For example:

param_db.commit_history(3, 6)
[CommitEntry(id=4, message='Increment param value to 4.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 210051, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=5, message='Increment param value to 5.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 214435, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=6, message='Increment param value to 6.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 219002, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC')))]

Note that the indices passed in are list indices, and do not necessarily correspond to commit IDs, whereas ParamDB.load() takes in a specific commit ID.

Negative indices also are allowed and function like Python list slicing. For example, to get the last three commits, we can pass in -3 for the start and leave the end as None.

param_db.commit_history(start=-3)
[CommitEntry(id=9, message='Increment param value to 9.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 231916, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=10, message='Increment param value to 10.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 235603, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC'))),
 CommitEntry(id=11, message='Increment param value to 11.23', timestamp=datetime.datetime(2024, 5, 8, 18, 17, 48, 239600, tzinfo=datetime.timezone(datetime.timedelta(0), 'UTC')))]