pyrqlite puts a Python cursor over the rqlite HTTP API
The new PyPI package makes rqlite accessible through familiar Python connection and cursor methods. Its transaction and parameter behavior still depend on the HTTP adapter's implementation.
A familiar client interface can hide useful transport details as well as reduce application code. Philip O'Toole's March 2 announcement credits Zac Medico with a new PyPI project and package for rqlite, pointing to pyrqlite 2.1. The package presents Python connection and cursor methods over the database's HTTP API. That makes it easier to begin using rqlite from Python, but the method names do not automatically give it every behavior of a local SQLite connection.
The versioned PyPI release was uploaded on February 28. March 2 is the maintainer's announcement date, which is the event here. Keeping those dates distinct avoids calling this a new server release or implying that the package first became downloadable on the announcement day.
I like rqlite's small relational-service model. A Python adapter makes that model available through an interface many applications already understand. Its value depends on stating where the adapter follows familiar conventions and where a request to a distributed service has different behavior.
A cursor translates operations into HTTP requests
The 2.1 source distribution includes its README and implementation. Its example connects through pyrqlite.dbapi2, opens cursors with a context manager, and fetches a record after executing a query. The connection defaults to HTTP on localhost port 4001.
import pyrqlite.dbapi2 as dbapi2
connection = dbapi2.connect(host="localhost", port=4001)
try:
with connection.cursor() as cursor:
cursor.execute("SELECT 1 AS value")
print(cursor.fetchone())
finally:
connection.close()
This example follows the package's connection and cursor pattern without requiring an existing application table. Inside execute, the adapter identifies the SQL command by its first word. It sends SELECT and PRAGMA through a GET request to /db/query. Other commands go to /db/execute?transaction as JSON in a POST request.
That classification is an implementation rule worth knowing. The package does not determine statement behavior by asking SQLite to prepare the query locally. It inspects the leading command and selects a remote endpoint. An application adopting the adapter needs its statement forms to agree with that rule.
The cursor decodes the response and constructs rows from the returned column names and values. Its fetch methods then consume rows already held by the cursor. A cursor-shaped API therefore does not imply a server-side streaming cursor. In this implementation, HTTP response decoding precedes the application's calls to fetch individual rows.
Parameters are handled by the client
The README advertises qmark and named parameter styles. The 2.1 code implements both through _substitute_params, which adapts Python values and substitutes them into the operation before sending the request. Named parameters use a dictionary, while qmark parameters use a sequence. Mismatched forms or missing parameters can raise a programming error.
This means support for named arguments in the Python package should not be described as evidence of server-native named bindings. The package prepares a SQL string itself. Its behavior comes from the adapter's matching and value-adaptation code, not merely from SQLite's ability to recognize parameter tokens.
The distinction matters when assessing compatibility. A client can provide a convenient named interface over a server protocol that receives completed SQL. Another client might send SQL and parameter values separately. Those are different implementations even if the Python call at the application boundary looks similar.
A connection does not create a multi-call transaction
The README states that transactions are unsupported. The implementation makes commit and rollback no-ops. Their presence therefore does not establish that a sequence of earlier cursor calls can later be committed or undone together.
There is a narrower transaction behavior in the HTTP adapter. executemany builds a list of substituted statements and submits that list in one request to /db/execute?transaction. The server's transaction request applies to that submitted batch. It is different from keeping a transaction open across separate application calls on the Python connection.
I consider this the most useful limitation to state early. Familiar commit() syntax can suggest a guarantee that the implementation explicitly does not provide. Applications that require several changes to succeed as one unit need to express that unit through supported server-request behavior, rather than assuming the client connection carries a transaction across requests.
The transport code also retries requests after connection exceptions and follows HTTP 301 redirects when a location is supplied. These are client responsibilities with observable effects. A retry cannot, by itself, prove that a previous write did not reach the server, and the implementation shown does not attach an operation identity that establishes deduplication.
Connection arguments include a timeout and a maximum redirect count. Those options control transport behavior separately from the SQL operation and its result rows.
The package makes rqlite easier to call from Python by providing connection setup, request construction, and row handling. Its source also gives a concrete account of the limits, parameters become client-prepared SQL, fetches read decoded rows, and transaction scope belongs to an individual submitted batch rather than a later commit() call.