Skip to main content

Lib/sqlite3/__init__.py

cpython 3.14 @ ab2d84fe1023/Lib/sqlite3/__init__.py

Lib/sqlite3/__init__.py is a 32-line shim that imports _sqlite3 (the C extension in Modules/_sqlite/) and re-exports its public names. All the real work is in the C extension; the Python layer only sets apilevel, threadsafety, paramstyle, and the default connect function.

The sqlite3 package is organized as three layers. The bottom layer is the SQLite amalgamation (Modules/_sqlite/clinic/ and the vendored Modules/_sqlite/sqlite3.c), which ships as a single C source file compiled into CPython on platforms that do not have a system libsqlite3. The middle layer is Modules/_sqlite/ which provides the Python types: Connection, Cursor, Row, Statement, Blob, and the exception hierarchy. The top layer is Lib/sqlite3/ which holds the Python-level __init__.py and dbapi2.py.

connect is the primary entry point. Its signature matches the DB-API 2.0 specification (PEP 249): connect(database, timeout=5.0, detect_types=0, isolation_level="", check_same_thread=True, factory=Connection, cached_statements=128, uri=False). The factory parameter lets callers substitute a custom Connection subclass without losing the C-level fast path.

Connection exposes the full DB-API 2.0 interface plus several SQLite-specific extensions: create_function, create_aggregate, create_collation, set_authorizer, set_progress_handler, set_trace_callback, enable_load_extension (if compiled in), load_extension, iterdump, backup, and blobopen. In CPython 3.12+ Connection gained the context-manager protocol directly (previously contextlib.closing was required).

Cursor follows DB-API 2.0: execute, executemany, executescript, fetchone, fetchmany, fetchall, close, and the read-only attributes description, rowcount, and lastrowid.

Row is a sequence-and-mapping hybrid: it supports integer indexing, slice indexing, and case-insensitive column-name lookup via row["Name"]. It compares equal to tuples with the same values.

Map

LinesSymbolRolegopy
1-10file header / _sqlite3 importImports the C extension and captures the module reference.module/sqlite3/module.go
11-20apilevel, threadsafety, paramstyleDB-API 2.0 module-level attributes; apilevel="2.0", threadsafety=1, paramstyle="qmark".module/sqlite3/module.go
21-32connect, Connection, Cursor, Row, exception re-exportsRe-exports from _sqlite3; connect is a direct alias for _sqlite3.connect.module/sqlite3/module.go

Reading

connect and Connection lifetime (C extension)

cpython 3.14 @ ab2d84fe1023/Lib/sqlite3/dbapi2.py#L1-30

# DB-API 2.0 compliance attributes
apilevel = "2.0"
threadsafety = 1 # Threads may share the module but not connections
paramstyle = "qmark"

from _sqlite3 import *
from _sqlite3 import (
_deprecated_names,
connect as _connect,
)

def connect(database, timeout=5.0, detect_types=0,
isolation_level="",
check_same_thread=True,
factory=None, cached_statements=128, uri=False):
if factory is None:
return _connect(database, timeout, detect_types,
isolation_level, check_same_thread,
cached_statements, uri)
return factory(database, timeout, detect_types,
isolation_level, check_same_thread,
cached_statements, uri)

connect opens (or creates) a SQLite database at database. Passing ":memory:" gives an in-process database with no file backing. The uri=True flag allows SQLite URI syntax: file:///tmp/test.db?mode=ro opens read-only.

timeout is the number of seconds to wait for a lock before raising OperationalError. isolation_level controls auto-commit: the empty string "" is the DB-API default (deferred transactions); None disables implicit BEGIN, putting the connection in autocommit mode. check_same_thread=True (the default) raises ProgrammingError if the connection is accessed from a thread other than the one that created it.

After connect, the connection object must be closed explicitly or used as a context manager. with sqlite3.connect(db) as con: commits on clean exit and rolls back on exception, but does not close the connection; call con.close() separately.

Cursor.execute and parameter binding

cpython 3.14 @ ab2d84fe1023/Modules/_sqlite/cursor.c#L1-60

# Example usage
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)")
con.execute("INSERT INTO t VALUES (?, ?)", (1, "hello"))
con.execute("INSERT INTO t VALUES (?, ?)", (2, "world"))

cur = con.cursor()
cur.execute("SELECT id, val FROM t WHERE id = ?", (1,))
row = cur.fetchone()
print(row) # (1, 'hello')
print(cur.description)
# (('id', None, None, None, None, None, None),
# ('val', None, None, None, None, None, None))

execute accepts a SQL string and an optional sequence or mapping of parameters. The qmark style uses ? as positional placeholders; named style (:name or @name) uses a dict. Parameters are converted from Python types to SQLite types by a built-in adapter table: None maps to NULL, int to INTEGER, float to REAL, str to TEXT, bytes to BLOB. Custom types register via register_adapter.

executemany(sql, seq_of_params) iterates seq_of_params and calls the C-level execute loop once per item. It is substantially faster than a Python loop over execute because the SQL is only parsed once.

executescript(sql_script) issues a COMMIT first, then executes the entire script as a sequence of statements separated by semicolons. It bypasses the adapter/converter machinery and ignores isolation_level.

Custom functions and aggregates

cpython 3.14 @ ab2d84fe1023/Modules/_sqlite/connection.c#L1-80

import sqlite3, math

con = sqlite3.connect(":memory:")

# Scalar function
con.create_function("sin", 1, math.sin)
con.execute("SELECT sin(1.5708)").fetchone() # (1.0,)

# Deterministic function (SQLite may cache the result for identical inputs)
con.create_function("upper2", 1, str.upper, deterministic=True)

# Aggregate
class StdDev:
def __init__(self):
self.vals = []
def step(self, val):
self.vals.append(val)
def finalize(self):
if not self.vals:
return None
n = len(self.vals)
mean = sum(self.vals) / n
return math.sqrt(sum((v - mean)**2 for v in self.vals) / n)

con.create_aggregate("stddev", 1, StdDev)
con.execute("CREATE TABLE nums (x REAL)")
con.executemany("INSERT INTO nums VALUES (?)", [(1.0,),(2.0,),(3.0,)])
con.execute("SELECT stddev(x) FROM nums").fetchone() # (0.816...,)

# Collation
con.create_collation("nocase_de", lambda a, b: (a.lower() > b.lower()) - (a.lower() < b.lower()))

create_function(name, num_params, func, *, deterministic=False) registers func as a SQLite scalar function. num_params=-1 means variadic. The deterministic flag hints to SQLite's query planner that the function has no side effects and always returns the same output for the same inputs, enabling additional optimizations.

create_aggregate(name, num_params, aggregate_class) registers a class whose instances accumulate values. SQLite calls step(value) for each row and finalize() once to retrieve the result. The class is instantiated fresh for each group.

create_collation(name, callable) registers a custom sort order. The callable receives two strings and returns a negative, zero, or positive integer (like the old cmp function). Collations are used in ORDER BY and CREATE INDEX ... COLLATE name.

Row and text_factory / row_factory

cpython 3.14 @ ab2d84fe1023/Modules/_sqlite/row.c#L1-50

con = sqlite3.connect(":memory:")
con.row_factory = sqlite3.Row
con.execute("CREATE TABLE p (name TEXT, age INT)")
con.execute("INSERT INTO p VALUES ('Alice', 30)")
row = con.execute("SELECT * FROM p").fetchone()
print(row["name"]) # Alice
print(row["NAME"]) # Alice (case-insensitive)
print(row[0]) # Alice
print(tuple(row)) # ('Alice', 30)

# Custom row factory
con.row_factory = lambda cur, row: dict(zip([d[0] for d in cur.description], row))
row = con.execute("SELECT * FROM p").fetchone()
print(row) # {'name': 'Alice', 'age': 30}

# text_factory: controls how TEXT columns are decoded
con.text_factory = bytes # return raw bytes instead of str
con.text_factory = str # default
con.text_factory = lambda b: b.decode("latin-1")

row_factory is called with (cursor, row_tuple) for every row returned by a query. Setting it to sqlite3.Row activates the built-in Row type which supports named-column access. Setting it to a lambda or function builds whatever Python object the caller prefers.

text_factory is called with the raw bytes of each TEXT column. The default is str (UTF-8 decode). Setting it to bytes skips decoding entirely, which is useful for binary data stored in TEXT columns or for databases with non-UTF-8 encodings.

In gopy, module/sqlite3/module.go is pending and requires either CGo bindings to libsqlite3 or a pure-Go SQLite driver such as modernc.org/sqlite.