bindings/python: Rename package to pyturso

This commit is contained in:
Pekka Enberg
2025-06-27 10:58:57 +03:00
parent e23835ed8e
commit a5b539f1bf
24 changed files with 64 additions and 247 deletions

2
Cargo.lock generated
View File

@@ -2716,7 +2716,7 @@ dependencies = [
] ]
[[package]] [[package]]
name = "py-limbo" name = "py-turso"
version = "0.0.22" version = "0.0.22"
dependencies = [ dependencies = [
"anyhow", "anyhow",

View File

@@ -125,9 +125,9 @@ pip install pylimbo
Example usage: Example usage:
```python ```python
import limbo import turso
con = limbo.connect("sqlite.db") con = turso.connect("sqlite.db")
cur = con.cursor() cur = con.cursor()
res = cur.execute("SELECT * FROM users") res = cur.execute("SELECT * FROM users")
print(res.fetchone()) print(res.fetchone())

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env -S python3 -u #!/usr/bin/env -S python3 -u
import limbo import turso
from antithesis.assertions import always from antithesis.assertions import always
try: try:
con = limbo.connect("bank_test.db") con = turso.connect("bank_test.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env -S python3 -u #!/usr/bin/env -S python3 -u
import limbo import turso
from antithesis.assertions import always from antithesis.assertions import always
try: try:
con = limbo.connect("bank_test.db") con = turso.connect("bank_test.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env -S python3 -u #!/usr/bin/env -S python3 -u
import limbo import turso
from antithesis.assertions import always from antithesis.assertions import always
try: try:
con = limbo.connect("bank_test.db") con = turso.connect("bank_test.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env -S python3 -u #!/usr/bin/env -S python3 -u
import limbo import turso
from antithesis.random import get_random from antithesis.random import get_random
try: try:
con = limbo.connect("bank_test.db") con = turso.connect("bank_test.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)

View File

@@ -3,7 +3,7 @@
import logging import logging
from logging.handlers import RotatingFileHandler from logging.handlers import RotatingFileHandler
import limbo import turso
from antithesis.random import get_random from antithesis.random import get_random
handler = RotatingFileHandler( handler = RotatingFileHandler(
@@ -17,7 +17,7 @@ logger.setLevel(logging.INFO)
logger.addHandler(handler) logger.addHandler(handler)
try: try:
con = limbo.connect("bank_test.db") con = turso.connect("bank_test.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)

View File

@@ -1,7 +1,7 @@
[project] [project]
dependencies = [ dependencies = [
"antithesis>=0.1.17", "antithesis>=0.1.17",
"pylimbo" "pyturso"
] ]
description = "Add your description here" description = "Add your description here"
name = "antithesis-tests" name = "antithesis-tests"
@@ -9,4 +9,4 @@ requires-python = ">=3.13"
version = "0.1.0" version = "0.1.0"
[tool.uv.sources] [tool.uv.sources]
pylimbo = { workspace = true } pyturso = { workspace = true }

View File

@@ -4,7 +4,7 @@ import glob
import json import json
import os import os
import limbo import turso
from antithesis.random import get_random, random_choice from antithesis.random import get_random, random_choice
constraints = ["NOT NULL", ""] constraints = ["NOT NULL", ""]
@@ -25,7 +25,7 @@ for f in glob.glob("*.db-wal"):
# store initial states in a separate db # store initial states in a separate db
try: try:
con_init = limbo.connect("init_state.db") con_init = turso.connect("init_state.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)
@@ -35,7 +35,7 @@ cur_init.execute("CREATE TABLE schemas (schema TEXT, tbl INT)")
cur_init.execute("CREATE TABLE tables (count INT)") cur_init.execute("CREATE TABLE tables (count INT)")
try: try:
con = limbo.connect("stress_composer.db") con = turso.connect("stress_composer.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)

View File

@@ -2,13 +2,13 @@
import json import json
import limbo import turso
from antithesis.random import get_random from antithesis.random import get_random
from utils import generate_random_value from utils import generate_random_value
# Get initial state # Get initial state
try: try:
con_init = limbo.connect("init_state.db") con_init = turso.connect("init_state.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)
@@ -25,7 +25,7 @@ pk = tbl_schema["pk"]
cols = [f"col_{col}" for col in range(tbl_schema["colCount"]) if col != pk] cols = [f"col_{col}" for col in range(tbl_schema["colCount"]) if col != pk]
try: try:
con = limbo.connect("stress_composer.db") con = turso.connect("stress_composer.db")
except Exception as e: except Exception as e:
print(f"Failed to open stress_composer.db. Exiting... {e}") print(f"Failed to open stress_composer.db. Exiting... {e}")
exit(0) exit(0)

View File

@@ -2,13 +2,13 @@
import json import json
import limbo import turso
from antithesis.random import get_random from antithesis.random import get_random
from utils import generate_random_value from utils import generate_random_value
# Get initial state # Get initial state
try: try:
con_init = limbo.connect("init_state.db") con_init = turso.connect("init_state.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)
@@ -21,7 +21,7 @@ tbl_schema = json.loads(cur_init.execute(f"SELECT schema FROM schemas WHERE tbl
cols = ", ".join([f"col_{col}" for col in range(tbl_schema["colCount"])]) cols = ", ".join([f"col_{col}" for col in range(tbl_schema["colCount"])])
try: try:
con = limbo.connect("stress_composer.db") con = turso.connect("stress_composer.db")
except Exception as e: except Exception as e:
print(f"Failed to open stress_composer.db. Exiting... {e}") print(f"Failed to open stress_composer.db. Exiting... {e}")
exit(0) exit(0)
@@ -39,7 +39,7 @@ for i in range(insertions):
INSERT INTO tbl_{selected_tbl} ({cols}) INSERT INTO tbl_{selected_tbl} ({cols})
VALUES ({", ".join(values)}) VALUES ({", ".join(values)})
""") """)
except limbo.OperationalError as e: except turso.OperationalError as e:
if "UNIQUE constraint failed" in str(e): if "UNIQUE constraint failed" in str(e):
# Ignore UNIQUE constraint violations # Ignore UNIQUE constraint violations
pass pass

View File

@@ -2,13 +2,13 @@
import json import json
import limbo import turso
from antithesis.assertions import always from antithesis.assertions import always
from antithesis.random import get_random from antithesis.random import get_random
# Get initial state # Get initial state
try: try:
con_init = limbo.connect("init_state.db") con_init = turso.connect("init_state.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)
@@ -21,7 +21,7 @@ tbl_schema = json.loads(cur_init.execute(f"SELECT schema FROM schemas WHERE tbl
cols = ", ".join([f"col_{col}" for col in range(tbl_schema["colCount"])]) cols = ", ".join([f"col_{col}" for col in range(tbl_schema["colCount"])])
try: try:
con = limbo.connect("stress_composer.db") con = turso.connect("stress_composer.db")
except Exception as e: except Exception as e:
print(f"Failed to open stress_composer.db. Exiting... {e}") print(f"Failed to open stress_composer.db. Exiting... {e}")
exit(0) exit(0)

View File

@@ -2,13 +2,13 @@
import json import json
import limbo import turso
from antithesis.random import get_random from antithesis.random import get_random
from utils import generate_random_value from utils import generate_random_value
# Get initial state # Get initial state
try: try:
con_init = limbo.connect("init_state.db") con_init = turso.connect("init_state.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)
@@ -21,7 +21,7 @@ tbl_schema = json.loads(cur_init.execute(f"SELECT schema FROM schemas WHERE tbl
cols = ", ".join([f"col_{col}" for col in range(tbl_schema["colCount"])]) cols = ", ".join([f"col_{col}" for col in range(tbl_schema["colCount"])])
try: try:
con = limbo.connect("stress_composer.db") con = turso.connect("stress_composer.db")
except Exception as e: except Exception as e:
print(f"Failed to open stress_composer.db. Exiting... {e}") print(f"Failed to open stress_composer.db. Exiting... {e}")
exit(0) exit(0)
@@ -39,7 +39,7 @@ for i in range(insertions):
INSERT INTO tbl_{selected_tbl} ({cols}) INSERT INTO tbl_{selected_tbl} ({cols})
VALUES ({", ".join(values)}) VALUES ({", ".join(values)})
""") """)
except limbo.OperationalError as e: except turso.OperationalError as e:
if "UNIQUE constraint failed" in str(e): if "UNIQUE constraint failed" in str(e):
# Ignore UNIQUE constraint violations # Ignore UNIQUE constraint violations
pass pass

View File

@@ -2,13 +2,13 @@
import json import json
import limbo import turso
from antithesis.random import get_random from antithesis.random import get_random
from utils import generate_random_value from utils import generate_random_value
# Get initial state # Get initial state
try: try:
con_init = limbo.connect("init_state.db") con_init = turso.connect("init_state.db")
except Exception as e: except Exception as e:
print(f"Error connecting to database: {e}") print(f"Error connecting to database: {e}")
exit(0) exit(0)
@@ -25,7 +25,7 @@ pk = tbl_schema["pk"]
cols = [f"col_{col}" for col in range(tbl_schema["colCount"]) if col != pk] cols = [f"col_{col}" for col in range(tbl_schema["colCount"]) if col != pk]
# print(cols) # print(cols)
try: try:
con = limbo.connect("stress_composer.db") con = turso.connect("stress_composer.db")
except Exception as e: except Exception as e:
print(f"Failed to open stress_composer.db. Exiting... {e}") print(f"Failed to open stress_composer.db. Exiting... {e}")
exit(0) exit(0)
@@ -53,7 +53,7 @@ for i in range(updates):
cur.execute(f""" cur.execute(f"""
UPDATE tbl_{selected_tbl} SET {set_clause} WHERE {where_clause} UPDATE tbl_{selected_tbl} SET {set_clause} WHERE {where_clause}
""") """)
except limbo.OperationalError as e: except turso.OperationalError as e:
if "UNIQUE constraint failed" in str(e): if "UNIQUE constraint failed" in str(e):
# Ignore UNIQUE constraint violations # Ignore UNIQUE constraint violations
pass pass

View File

@@ -1,5 +1,5 @@
[package] [package]
name = "py-limbo" name = "py-turso"
version.workspace = true version.workspace = true
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
@@ -8,7 +8,7 @@ repository.workspace = true
publish = false publish = false
[lib] [lib]
name = "_limbo" name = "_turso"
crate-type = ["cdylib"] crate-type = ["cdylib"]
[features] [features]

View File

@@ -1,7 +1,7 @@
import limbo import turso
# Use the context manager to automatically close the connection # Use the context manager to automatically close the connection
with limbo.connect("sqlite.db") as con: with turso.connect("sqlite.db") as con:
cur = con.cursor() cur = con.cursor()
cur.execute(""" cur.execute("""
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (

View File

@@ -1,183 +0,0 @@
from typing import Any, List, Optional, Tuple
__version__: str
class Connection:
def cursor(self) -> "Cursor":
"""
Creates a new cursor object using this connection.
:return: A new Cursor object.
:raises InterfaceError: If the cursor cannot be created.
"""
...
def close(self) -> None:
"""
Closes the connection to the database.
:raises OperationalError: If there is an error closing the connection.
"""
...
def commit(self) -> None:
"""
Commits the current transaction.
:raises OperationalError: If there is an error during commit.
"""
...
def rollback(self) -> None:
"""
Rolls back the current transaction.
:raises OperationalError: If there is an error during rollback.
"""
...
class Cursor:
arraysize: int
description: Optional[
Tuple[
str,
str,
Optional[str],
Optional[str],
Optional[str],
Optional[str],
Optional[str],
]
]
rowcount: int
def execute(self, sql: str, parameters: Optional[Tuple[Any, ...]] = None) -> "Cursor":
"""
Prepares and executes a SQL statement using the connection.
:param sql: The SQL query to execute.
:param parameters: The parameters to substitute into the SQL query.
:raises ProgrammingError: If there is an error in the SQL query.
:raises OperationalError: If there is an error executing the query.
:return: The cursor object.
"""
...
def executemany(self, sql: str, parameters: Optional[List[Tuple[Any, ...]]] = None) -> None:
"""
Executes a SQL command against all parameter sequences or mappings found in the sequence `parameters`.
:param sql: The SQL command to execute.
:param parameters: A list of parameter sequences or mappings.
:raises ProgrammingError: If there is an error in the SQL query.
:raises OperationalError: If there is an error executing the query.
"""
...
def fetchone(self) -> Optional[Tuple[Any, ...]]:
"""
Fetches the next row from the result set.
:return: A tuple representing the next row, or None if no more rows are available.
:raises OperationalError: If there is an error fetching the row.
"""
...
def fetchall(self) -> List[Tuple[Any, ...]]:
"""
Fetches all remaining rows from the result set.
:return: A list of tuples, each representing a row in the result set.
:raises OperationalError: If there is an error fetching the rows.
"""
...
def fetchmany(self, size: Optional[int] = None) -> List[Tuple[Any, ...]]:
"""
Fetches the next set of rows of a size specified by the `arraysize` property.
:param size: Optional integer to specify the number of rows to fetch.
:return: A list of tuples, each representing a row in the result set.
:raises OperationalError: If there is an error fetching the rows.
"""
...
def close(self) -> None:
"""
Closes the cursor.
:raises OperationalError: If there is an error closing the cursor.
"""
...
# Exception classes
class Warning(Exception):
"""Exception raised for important warnings like data truncations while inserting."""
...
class Error(Exception):
"""Base class for all other error exceptions. Catch all database-related errors using this class."""
...
class InterfaceError(Error):
"""Exception raised for errors related to the database interface rather than the database itself."""
...
class DatabaseError(Error):
"""Exception raised for errors that are related to the database."""
...
class DataError(DatabaseError):
"""
Exception raised for errors due to problems with the processed data like division by zero, numeric value out of
range, etc.
"""
...
class OperationalError(DatabaseError):
"""
Exception raised for errors related to the databases operation, not necessarily under the programmer's control.
"""
...
class IntegrityError(DatabaseError):
"""Exception raised when the relational integrity of the database is affected, e.g., a foreign key check fails."""
...
class InternalError(DatabaseError):
"""
Exception raised when the database encounters an internal error, e.g., cursor is not valid anymore, transaction out
of sync.
"""
...
class ProgrammingError(DatabaseError):
"""
Exception raised for programming errors, e.g., table not found, syntax error in SQL, wrong number of parameters
specified.
"""
...
class NotSupportedError(DatabaseError):
"""Exception raised when a method or database API is used which is not supported by the database."""
...
def connect(path: str) -> Connection:
"""
Connects to a database at the specified path.
:param path: The path to the database file.
:return: A Connection object to the database.
:raises InterfaceError: If the database cannot be connected.
"""
...

View File

@@ -3,7 +3,7 @@ requires = ['maturin>=1,<2', 'typing_extensions']
build-backend = 'maturin' build-backend = 'maturin'
[project] [project]
name = 'pylimbo' name = 'pyturso'
description = "Limbo is a work-in-progress, in-process OLTP database management system, compatible with SQLite." description = "Limbo is a work-in-progress, in-process OLTP database management system, compatible with SQLite."
requires-python = '>=3.9' requires-python = '>=3.9'
classifiers = [ classifiers = [
@@ -45,7 +45,7 @@ Source = "https://github.com/tursodatabase/limbo"
[tool.maturin] [tool.maturin]
bindings = 'pyo3' bindings = 'pyo3'
module-name = "limbo._limbo" module-name = "turso._turso"
features = ["pyo3/extension-module"] features = ["pyo3/extension-module"]
[tool.pip-tools] [tool.pip-tools]
@@ -58,7 +58,7 @@ testpaths = 'tests'
log_format = '%(name)s %(levelname)s: %(message)s' log_format = '%(name)s %(levelname)s: %(message)s'
[tool.coverage.run] [tool.coverage.run]
source = ['limbo'] source = ['turso']
branch = true branch = true
[tool.coverage.report] [tool.coverage.report]

View File

@@ -1,13 +1,13 @@
coverage==7.6.1 coverage==7.6.1
# via # via
# pylimbo (pyproject.toml) # pyturso (pyproject.toml)
# pytest-cov # pytest-cov
iniconfig==2.0.0 iniconfig==2.0.0
# via pytest # via pytest
maturin==1.7.8 maturin==1.7.8
# via pylimbo (pyproject.toml) # via pyturso (pyproject.toml)
mypy==1.11.0 mypy==1.11.0
# via pylimbo (pyproject.toml) # via pyturso (pyproject.toml)
mypy-extensions==1.0.0 mypy-extensions==1.0.0
# via mypy # via mypy
packaging==24.2 packaging==24.2
@@ -16,13 +16,13 @@ pluggy==1.5.0
# via pytest # via pytest
pytest==8.3.1 pytest==8.3.1
# via # via
# pylimbo (pyproject.toml) # pyturso (pyproject.toml)
# pytest-cov # pytest-cov
pytest-cov==5.0.0 pytest-cov==5.0.0
# via pylimbo (pyproject.toml) # via pyturso (pyproject.toml)
ruff==0.5.4 ruff==0.5.4
# via pylimbo (pyproject.toml) # via pyturso (pyproject.toml)
typing-extensions==4.12.2 typing-extensions==4.12.2
# via # via
# mypy # mypy
# pylimbo (pyproject.toml) # pyturso (pyproject.toml)

View File

@@ -1,2 +1,2 @@
typing-extensions==4.12.2 typing-extensions==4.12.2
# via pylimbo (pyproject.toml) # via pyturso (pyproject.toml)

View File

@@ -365,7 +365,7 @@ fn py_to_owned_value(obj: &Bound<PyAny>) -> Result<limbo_core::Value> {
} }
#[pymodule] #[pymodule]
fn _limbo(m: &Bound<PyModule>) -> PyResult<()> { fn _turso(m: &Bound<PyModule>) -> PyResult<()> {
m.add("__version__", env!("CARGO_PKG_VERSION"))?; m.add("__version__", env!("CARGO_PKG_VERSION"))?;
m.add_class::<Connection>()?; m.add_class::<Connection>()?;
m.add_class::<Cursor>()?; m.add_class::<Cursor>()?;

View File

@@ -1,8 +1,8 @@
import os import os
import sqlite3 import sqlite3
import limbo
import pytest import pytest
import turso
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@@ -48,7 +48,7 @@ def setup_database():
print(f"Failed to clean up: {e}") print(f"Failed to clean up: {e}")
@pytest.mark.parametrize("provider", ["sqlite3", "limbo"]) @pytest.mark.parametrize("provider", ["sqlite3", "turso"])
def test_fetchall_select_all_users(provider, setup_database): def test_fetchall_select_all_users(provider, setup_database):
conn = connect(provider, setup_database) conn = connect(provider, setup_database)
cursor = conn.cursor() cursor = conn.cursor()
@@ -61,7 +61,7 @@ def test_fetchall_select_all_users(provider, setup_database):
assert users == [(1, "alice"), (2, "bob")] assert users == [(1, "alice"), (2, "bob")]
@pytest.mark.parametrize("provider", ["sqlite3", "limbo"]) @pytest.mark.parametrize("provider", ["sqlite3", "turso"])
def test_fetchall_select_user_ids(provider): def test_fetchall_select_user_ids(provider):
conn = connect(provider, "tests/database.db") conn = connect(provider, "tests/database.db")
cursor = conn.cursor() cursor = conn.cursor()
@@ -74,7 +74,7 @@ def test_fetchall_select_user_ids(provider):
assert user_ids == [(1,), (2,)] assert user_ids == [(1,), (2,)]
@pytest.mark.parametrize("provider", ["sqlite3", "limbo"]) @pytest.mark.parametrize("provider", ["sqlite3", "turso"])
def test_in_memory_fetchone_select_all_users(provider): def test_in_memory_fetchone_select_all_users(provider):
conn = connect(provider, ":memory:") conn = connect(provider, ":memory:")
cursor = conn.cursor() cursor = conn.cursor()
@@ -90,7 +90,7 @@ def test_in_memory_fetchone_select_all_users(provider):
assert alice == (1, "alice") assert alice == (1, "alice")
@pytest.mark.parametrize("provider", ["sqlite3", "limbo"]) @pytest.mark.parametrize("provider", ["sqlite3", "turso"])
def test_fetchone_select_all_users(provider): def test_fetchone_select_all_users(provider):
conn = connect(provider, "tests/database.db") conn = connect(provider, "tests/database.db")
cursor = conn.cursor() cursor = conn.cursor()
@@ -107,7 +107,7 @@ def test_fetchone_select_all_users(provider):
assert bob == (2, "bob") assert bob == (2, "bob")
@pytest.mark.parametrize("provider", ["sqlite3", "limbo"]) @pytest.mark.parametrize("provider", ["sqlite3", "turso"])
def test_fetchone_select_max_user_id(provider): def test_fetchone_select_max_user_id(provider):
conn = connect(provider, "tests/database.db") conn = connect(provider, "tests/database.db")
cursor = conn.cursor() cursor = conn.cursor()
@@ -120,8 +120,8 @@ def test_fetchone_select_max_user_id(provider):
assert max_id == (2,) assert max_id == (2,)
# Test case for: https://github.com/tursodatabase/limbo/issues/494 # Test case for: https://github.com/tursodatabase/turso/issues/494
@pytest.mark.parametrize("provider", ["sqlite3", "limbo"]) @pytest.mark.parametrize("provider", ["sqlite3", "turso"])
def test_commit(provider): def test_commit(provider):
conn = connect(provider, "tests/database.db") conn = connect(provider, "tests/database.db")
cur = conn.cursor() cur = conn.cursor()
@@ -158,7 +158,7 @@ def test_commit(provider):
assert record assert record
@pytest.mark.parametrize("provider", ["sqlite3", "limbo"]) @pytest.mark.parametrize("provider", ["sqlite3", "turso"])
def test_with_statement(provider): def test_with_statement(provider):
with connect(provider, "tests/database.db") as conn: with connect(provider, "tests/database.db") as conn:
cursor = conn.cursor() cursor = conn.cursor()
@@ -171,8 +171,8 @@ def test_with_statement(provider):
def connect(provider, database): def connect(provider, database):
if provider == "limbo": if provider == "turso":
return limbo.connect(database) return turso.connect(database)
if provider == "sqlite3": if provider == "sqlite3":
return sqlite3.connect(database) return sqlite3.connect(database)
raise Exception(f"Provider `{provider}` is not supported") raise Exception(f"Provider `{provider}` is not supported")

View File

@@ -1,4 +1,4 @@
from ._limbo import ( from ._turso import (
Connection, Connection,
Cursor, Cursor,
DatabaseError, DatabaseError,