bindings/python/py-bindings-db.mdx
Turso - is the SQLite compatible database written in Rust. One of the important features of the Turso - is async IO execution which can be used with modern storage backend like IO uring.
Your task is to generate Python driver with the API similar to the SQLite DB-api2
General rules for driver implementation you MUST follow and never go against these rules:
# all imports must be at the beginning - no imports in the middle of function
from typing import ...
from ._turso import ( ... )
# DB-API 2.0 module attributes
apilevel = "2.0"
...
# Exception hierarchy following DB-API 2.0
class Warning(Exception): ... # more
...
def _map_turso_exception(exc: Exception) -> Exception:
"""Maps Turso-specific exceptions to DB-API 2.0 exception hierarchy"""
if isinstance(exc, Busy): ...
...
# Connection goes FIRST
class Connection: ...
# Cursor goes SECOND
class Cursor: ...
# Row goes THIRD
class Row: ...
def connect(
path: str,
*,
experimental_features: Optional[str] = None,
isolation_level: Optional[str] = "DEFERRED",
extra_io: Optional[Callable[[], None]] = None # extra IO which must be called after stmt.run_io() invocations in the driver
): ...
# Make it easy to enable logging with native `logging` Python module
# (import logging only inside this function - make an exception here)
def setup_logging(level: Optional[int] = None) -> None: ...
PyTursoStatement::execute and PyTursoStatement::step methods: every statement must be either "stepped" or "executed"
execute ignores all rowsget_auto_commit method - otherwise it can be hard to properly implement implicit transaction rules of DB API2class T:
def f(self) -> 'T':
with ... as conn: ...class Row(Sequence[Any]):
def __new__(cls, cursor: Cursor, data: tuple[Any, ...], /) -> Self: ...
* Make typings compatible with official types:
<Link url="https://raw.githubusercontent.com/python/typeshed/refs/heads/main/stdlib/sqlite3/__init__.pyi" />
You must use bindings in the lib.rs written with pyo3 library which has certain conventions.
Remember, that it can accept py: Python argument which will be passed implicitly and exported bindings will not have this extra arg
Make driver API similar to the SQLite DB-API2 for the python.
Pay additional attention to the following aspects:
If autocommit is LEGACY_TRANSACTION_CONTROL, isolation_level is not None, sql is an INSERT, UPDATE, DELETE, or REPLACE statement, and there is no open transaction, a transaction is implicitly opened before executing sql.
executemany(...) methods as it must return rowcount of all executed statements (not just last statement)<Shell cmd="curl https://docs.python.org/3/library/sqlite3.html | pandoc --from html --to markdown" selector="~Connection objects|~Cursor objects|~Row objects|~Exceptions|~Transaction" ext=".md" />
</Code> </Output>