> Fetch the index of every Tonbo docs page as Markdown at https://tonbo.dev/llms.txt

# gate(), import and tokens

Last updated 3 November 2026

`gate()` holds a block’s outcome until `synced()`, `import_sqlite()` loads a plain SQLite file into a new database, and `set_token()` replaces the token the process sends.

## gate()

```python
@contextlib.contextmanager
def gate(*dbs: UrsulaConnection, timeout: float | None = None) -> Iterator[None]: ...
```

```python
with sqlite_ursula.gate(db):
    reply = handle(request)  # commits through db
send(reply)  # runs once Tonbo holds every commit the block made
```

Runs the block, then lets its outcome go on only once a [synced()](https://tonbo.dev/docs/reference/python/connection.md#synced) call made after the block ended returned on every database given, so nothing outside the process acts on a result, or an error, that rests on a commit Tonbo does not hold yet. A block that only read waits too: it may have read another connection’s pending commit.

| Parameter | Type | Default | What it does |
| --- | --- | --- | --- |
| `*dbs` | `UrsulaConnection` | Required | One or more connections `open()` or `aopen()` made. The wait covers every one at once. None at all, or any other object, raises `invalid_argument`. |
| `timeout` | `float \| None` | `None`: no limit | How many seconds the wait after the block may take, zero or more; it does not bound the block. Past it, `TimeoutError`, while the commits keep replicating. |

- An [UrsulaError](https://tonbo.dev/docs/reference/python/errors.md#ursula-error) the block raises passes at once, as it was raised, also when a library wrapped it (as `__cause__`, SQLAlchemy’s `.orig`, or in an `ExceptionGroup`): a refused write committed nothing, and a reset is what the wait would report. So does a SQLite error of a framework’s own connection that is a refused write or a reset.
- Every other `Exception` waits as a result does, then passes. Ctrl-C, a cancellation and `SystemExit` pass at once.
- The first failure on any database, such as a reset, ends the wait and raises instead of the outcome.
- Effects inside the block, such as an outbound call, are not gated: call `db.synced()` before them. To make such a call once across crashes, see [Run side effects once](https://tonbo.dev/docs/databases/side-effects.md).
- It raises [`invalid_argument`](https://tonbo.dev/docs/reference/python/errors.md#setup-invalid-argument) before the block runs when given no database, or one `open()` did not make.

## agate()

```python
@contextlib.asynccontextmanager
async def agate(
    *dbs: UrsulaConnection,
    timeout: float | None = None,
) -> AsyncIterator[None]: ...
```

```python
async with sqlite_ursula.agate(db, timeout=10):
    reply = await handle(request)  # commits through db
await send(reply)
```

[gate()](#gate) for asyncio, as `async with`: the same [parameters](#gate-dbs) and the same rules, and it waits on the event loop instead of blocking it. Cancelling the task ends the wait.

## import_sqlite()

```python
def import_sqlite(
    url: str,
    file: str | os.PathLike[str],
    *,
    token: str | None = None,
    timeout: float = DEFAULT_IMPORT_S,
) -> Imported: ...
```

Imports the plain SQLite database `file` into the database at `url`, as its first snapshot, page for page; then [open()](https://tonbo.dev/docs/reference/python/open.md#open) it as any other. On Tonbo, create the database first (see [Manage databases](https://tonbo.dev/docs/databases/manage.md#create)): it starts empty, and the import fills it. `VACUUM INTO`, run on the source database with any SQLite, writes a copy with 4096-byte pages and no `-wal`:

```text
PRAGMA page_size = 4096;
VACUUM INTO '/tmp/notes-import.db';
```

```python
import os

import sqlite_ursula

done = sqlite_ursula.import_sqlite(
    os.environ["NOTES_URL"],
    "/tmp/notes-import.db",
    token=os.environ["TONBO_API_KEY"],
)
print(done.pages, done.bytes)
db = sqlite_ursula.open(os.environ["NOTES_URL"], token=os.environ["TONBO_API_KEY"])
```

| Parameter | Type | Default | What it does |
| --- | --- | --- | --- |
| `url` | `str` | Required | The URL of the database to fill: one you created, still empty. |
| `file` | `str \| os.PathLike[str]` | Required | The plain SQLite file, a path. It must have 4096-byte pages, with no `-wal` beside it and no hot journal. It is only read. |
| `token` | `str \| None` | `None`: the token the process holds | The bearer token of the import’s requests alone; it does not change the process’s. A string. An access token lasts 10 minutes, so for a longer import pass a key that acts as you. |
| `timeout` | `float` | `600`: seconds, 10 minutes | How many seconds the import may take: a positive number. |

- It blocks the calling thread until the import is done, for at most `timeout`. The token needs to write the database.
- The database must be empty. A stream that is not a database’s raises [`stream_format`](https://tonbo.dev/docs/reference/python/errors.md#setup-stream-format), and anything else [`stream_state`](https://tonbo.dev/docs/reference/python/errors.md#setup-stream-state), with nothing published.
- While it runs, opens of the database raise `stream_state`. An import that fails after it claimed the database leaves one that refuses opens and imports until it is deleted and created again, so an [UrsulaUnavailableError](https://tonbo.dev/docs/reference/python/errors.md#ursula-unavailable-error) from an import says `fix`.
- A snapshot larger than one request goes up in parts. How large a database may grow is on [Limits](https://tonbo.dev/docs/databases/limits.md#size).
- It raises [UrsulaSetupError](https://tonbo.dev/docs/reference/python/errors.md#ursula-setup-error), such as [`invalid_argument`](https://tonbo.dev/docs/reference/python/errors.md#setup-invalid-argument) for the file, [`local_setup`](https://tonbo.dev/docs/reference/python/errors.md#setup-local-setup) when it cannot read it, [`protocol_mismatch`](https://tonbo.dev/docs/reference/python/errors.md#setup-protocol-mismatch) or [`forked`](https://tonbo.dev/docs/reference/python/errors.md#setup-forked), and [UrsulaUnavailableError](https://tonbo.dev/docs/reference/python/errors.md#ursula-unavailable-error) when Tonbo did not answer in time (see [Troubleshooting](https://tonbo.dev/docs/databases/troubleshooting/open.md#unavailable)).
- It is not idempotent: once it succeeded, a second import of the database raises `stream_state`. After a failure that published nothing, call it again; after one that left the claim, delete the database, create it again and import again.

To export a database to a plain SQLite file, see [Export a copy](https://tonbo.dev/docs/databases/backups.md#export).

### Imported

```python
@dataclass(frozen=True)
class Imported:
    offset: int
    digest: str
    pages: int
    bytes: int
```

What the import published, the database’s first snapshot. A frozen dataclass.

| Field | Type | What it holds |
| --- | --- | --- |
| `offset` | `int` | The snapshot's offset in the database's stream, the end of the import's claim. |
| `digest` | `str` | The snapshot's digest. |
| `pages` | `int` | How many 4096-byte pages it holds. |
| `bytes` | `int` | The compressed snapshot's size, in bytes. |

## set_token()

```python
def set_token(token: str | None) -> None: ...
```

```python
import sqlite_ursula

# Every 5 minutes, with an access token exchanged from an Agent's key:
sqlite_ursula.set_token(exchange(agent_key))
```

Sets the bearer token every request of the process carries from now on, for every database it has open, and sends again at once the requests Tonbo refused with `401`. The process holds one token: the last `set_token()`’s, or the last [open()](https://tonbo.dev/docs/reference/python/open.md#open-token)’s with a `token`, applies. Use it for a token that changes, such as an access token exchanged from an Agent’s key, which lasts 10 minutes: exchange the key again before it expires and pass the new token here, or commits wait until you do (see [The token exchange](https://tonbo.dev/docs/platform/api-keys.md#exchange)).

| Parameter | Type | Default | What it does |
| --- | --- | --- | --- |
| `token` | `str \| None` | Required | The new bearer token, a string. `None` or `""` goes back to the file `URSULA_VFS_TOKEN_FILE` names, when set. Anything else raises `invalid_argument`. |

It returns `None`. Setting the same token again changes nothing. It raises [`forked`](https://tonbo.dev/docs/reference/python/errors.md#setup-forked) in a forked child, and `invalid_argument` for a token that is not a string. A token Tonbo refuses shows as [unauthorized](https://tonbo.dev/docs/databases/troubleshooting/open.md#unauthorized) in `status()["replication"]["condition"]`, while commits wait.
