Skip to content

Save and reopen your work

A Store created with sync=True shares changes with Python, but disappears when its session ends. Let's save one and check that an edit survives reopening it.

Save a Store

Run this in a notebook, using a new filename for the first save

from pret import DataFrame, create_store, load_store, save_store

store = create_store(
    {
        "title": "My todos",
        "todos": DataFrame(
            [
                {"todo_id": 1, "text": "My first todo", "done": True},
                {"todo_id": 2, "text": "My second todo", "done": False},
            ]
        ),
    },
    sync=True,
)
saved = save_store(store, "todos.pret")

todos.pret is a SQLite database, a file containing the Store's values, table rows and saved edit history. No separate database server is needed.

save_store returns a new Store connected to that file. Use saved in subsequent code and widgets. The original store remains separate. Saving to an existing filename raises FileExistsError, so rerun the next section with load_store when the file already exists.

Edit and reopen it

saved["title"] = "Weekend todos"
saved["todos"].update(identity={"todo_id": 2}, values={"done": True})

reopened = load_store("todos.pret")
print(reopened["title"])
print(reopened["todos"].materialize().to_pylist())
Weekend todos
[{'todo_id': 1, 'text': 'My first todo', 'done': True}, {'todo_id': 2, 'text': 'My second todo', 'done': True}]

The title is Weekend todos, and the second todo has done=True. Changes made through saved or reopened are written to the file automatically. There is no second save call after each edit. You can run the load_store lines in a fresh Python session and see the same result.

For a pandas result, use reopened["todos"].materialize().to_pandas(). This collects the current rows, so select a manageable dataset before exporting a large table.

Start directly with a saved Store

You can also create or reopen a Store in one call

todo_list = create_store(lambda: {"title": "My todos", "remaining": 0}, sync="my-todos.pret")

The function supplies the initial data only when the file is new. If my-todos.pret already exists, Pret loads its saved contents. This also works with DataFrames built from records, pandas or Arrow. For Spark and Ibis queries, use the explicit editable copy workflow. Attaching a live query to a saved Store does not save its source rows or database connection.

What is inside the file?

todos.pret is a SQLite database, any SQLite tool can open it

import sqlite3

with sqlite3.connect("todos.pret") as connection:
    print(connection.execute("SELECT * FROM todos").fetchall())
    print(connection.execute("SELECT json_extract(value, '$.data.title') FROM _pret_state").fetchone())
[(1, 'My first todo', 1), (2, 'My second todo', 1)]
('Weekend todos',)

The todos DataFrame is readable as a SQL view of the same name, where done is stored as 0 or 1. Ordinary values such as title are not columns, they are part of one JSON document, which SQLite reads with json_extract.

Read the file with SQL, but edit it through Pret, so that connected notebooks and widgets see the change and undo keeps working. Inside a Store file explains where each kind of value is stored and what the other _pret_ tables are for.

Suppose finishing a todo also changes the list title. Group both edits with transact

from pret.store import transact

with transact(saved):
    saved["todos"].update(identity={"todo_id": 1}, values={"done": False})
    saved["title"] = "Todos to redo"

This group is a transaction. Pret commits both changes to SQLite together, then notifies other connected views. If the block fails, Pret restores the previous values.

Open the same work in another notebook

Run load_store("todos.pret") in another notebook on the same filesystem. Each notebook has its own Python Store, and Pret watches the shared file for committed changes. An edit in either notebook updates the other Store and its connected widgets.

Both notebooks must use the same file. Copying todos.pret elsewhere creates a separate dataset, which does not continue synchronizing with the original.

Read a copy without connecting

load_store_snapshot(path) returns a Python copy of the values without subscribing to updates. DataFrames in the copy hold their rows in memory, use materialize() to read them.

from pret import load_store_snapshot

copy = load_store_snapshot("todos.pret")
print(copy["title"], copy["todos"].materialize().num_rows)
Todos to redo 2

To edit these tables in a JupyterLab tab, continue with Metanno's walkthrough.