This release is a pre-release and may not be stable for production use.
pyxpo-sqlite
SQLite databases that persist across app restarts, for pyxpo apps. The API
follows expo-sqlite. The phone's Python ships the sqlite3
module, so this package is pure Python: no native code and no rebuild of the native shell.
pip install pyxpo-sqlite
[tool.pyxpo]
modules = ["sqlite"]
import pyxpo_sqlite as SQLite
db = await SQLite.open_database_async("app.db")
await db.exec_async("""
PRAGMA journal_mode = WAL;
CREATE TABLE IF NOT EXISTS todo (id INTEGER PRIMARY KEY, title TEXT NOT NULL, done INTEGER DEFAULT 0);
""")
res = await db.run_async("INSERT INTO todo (title) VALUES (?)", "Buy milk")
print(res.last_insert_row_id, res.changes)
row = await db.get_first_async("SELECT * FROM todo WHERE id = ?", res.last_insert_row_id) # dict or None
rows = await db.get_all_async("SELECT * FROM todo WHERE done = $done", {"$done": 0}) # list of dicts
async for row in db.get_each_async("SELECT * FROM todo"): # one at a time
...
async def mark_all():
await db.run_async("UPDATE todo SET done = 1")
await db.with_transaction_async(mark_all) # COMMIT, or ROLLBACK if mark_all raises
Functions
| Function | Notes |
|---|---|
open_database_async(name, options=None, directory=None) |
Opens or creates name in directory (default default_database_directory). ":memory:" opens a private in-memory database. Opening the same file again returns the same connection unless SQLiteOpenOptions(use_new_connection=True). |
delete_database_async(name, directory=None) |
Deletes the file and its -wal, -shm and -journal files. Raises while the database is open. |
deserialize_database_async(data) |
An in-memory database holding data from serialize_async(). |
default_database_directory |
<documents>/SQLite: the app's Documents folder on iOS, filesDir on Android. |
SQLiteDatabase
| Method | Notes |
|---|---|
exec_async(sql) |
Runs ;-separated statements without values or results (schema, PRAGMA). |
run_async(sql, *values) |
Returns SQLiteRunResult(last_insert_row_id, changes). |
get_first_async(sql, *values) |
First row as a dict, or None. |
get_all_async(sql, *values) |
All rows as dicts. |
get_each_async(sql, *values) |
Async iterator of rows, read in small batches. |
prepare_async(sql) |
SQLiteStatement: execute_async(*values) returns a result with last_insert_row_id, changes, get_first_async(), get_all_async() and async iteration; also get_column_names_async() and finalize_async(). |
with_transaction_async(task) |
Runs await task() inside BEGIN/COMMIT, rolling back if it raises. Queries from other tasks on the same connection meanwhile join the transaction. |
with_exclusive_transaction_async(task) |
Runs await task(txn) on a separate connection inside BEGIN EXCLUSIVE; run queries on txn only. Not for ":memory:". |
is_in_transaction_async() |
|
serialize_async(name="main") |
The database as bytes. |
close_async() |
A shared connection closes when every opener closed it. |
database_path, database_name |
Values: positional (run_async(sql, 1, "a")), one list or tuple, or one dict for named parameters. Dict keys may
keep the prefix used in the SQL ({"$id": 1} for $id, :id, @id) or drop it. Rows map column names to
Python values: int, float, str, bytes or None.
Every method also has a _sync form that blocks (for example get_all_sync), and camelCase names work
(getAllAsync, runAsync, lastInsertRowId). Async methods run on one worker thread per connection, so the UI
stays responsive. SQL errors raise the sqlite3 exceptions (sqlite3.OperationalError,
sqlite3.IntegrityError, ...).
Provider and hook
from pyxpo_sqlite import SQLiteProvider, use_sqlite_context
async def migrate(db):
await db.exec_async("CREATE TABLE IF NOT EXISTS todo (id INTEGER PRIMARY KEY, title TEXT)")
def App():
return SQLiteProvider(TodoList(), database_name="app.db", on_init=migrate, fallback=Text("Loading..."))
@component
def TodoList():
db = use_sqlite_context()
...
SQLiteProvider props: database_name, options, directory, on_init(db) (awaited before the children render),
on_error(error) (without it the error is raised to the nearest ErrorBoundary) and fallback.
Not supported
Change listeners (addDatabaseChangeListener), enableChangeListener, SQLCipher encryption, loading extensions
and the key-value Storage export of expo-sqlite (use pyxpo-storage).
Platforms
iOS, Android and desktop. The bundled Python on iOS and Android is 3.13. On desktop, serialize and
deserialize need Python 3.11 or later and raise sqlite3.NotSupportedError before that. On desktop, databases
live in .pyxpo-data/documents/SQLite under the working directory.
Metadata
Release files for pyxpo-sqlite 0.1.0a1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyxpo_sqlite-0.1.0a1.tar.gz | 11.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyxpo_sqlite-0.1.0a1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 22.3 kB
Release files / pyxpo_sqlite-0.1.0a1.tar.gz
| Download URL | pyxpo_sqlite-0.1.0a1.tar.gz |
|---|---|
| Size | 11.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
83efa9e71ca1c6bd349db475e9bd9a3cf1197338e484ca657061f4d1b90a08ca
|
|
BLAKE2b-256 checksum How to use checksums |
f40ae199314b15538df0a8e5019f9e7d1e91775fccdd26a96e9b45fc7e6d208d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency logRelease files / pyxpo_sqlite-0.1.0a1-py3-none-any.whl
| Download URL | pyxpo_sqlite-0.1.0a1-py3-none-any.whl |
|---|---|
| Size | 10.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5b4781f952ec55aa56b12bf88f783336c199ade54a90d9089d4c6a4d7e539ad1
|
|
BLAKE2b-256 checksum How to use checksums |
834af9a316ba563138f39aebab13af4d19f18811df1233943af712e542611bea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.
Transparency log