dqlite-dbapi 0.1.2__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/PKG-INFO +1 -1
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/pyproject.toml +1 -1
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/src/dqlitedbapi/__init__.py +1 -1
- dqlite_dbapi-0.1.3/src/dqlitedbapi/aio/__init__.py +95 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/src/dqlitedbapi/aio/connection.py +25 -17
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/src/dqlitedbapi/aio/cursor.py +1 -4
- dqlite_dbapi-0.1.2/src/dqlitedbapi/aio/__init__.py +0 -43
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/.github/workflows/publish-to-pypi.yml +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/.gitignore +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/DEVELOPMENT.md +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/LICENSE.md +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/README.md +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/src/dqlitedbapi/connection.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/src/dqlitedbapi/cursor.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/src/dqlitedbapi/exceptions.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/src/dqlitedbapi/py.typed +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/src/dqlitedbapi/types.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/tests/__init__.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/tests/conftest.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/tests/integration/__init__.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/tests/integration/conftest.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/tests/integration/test_returning.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/tests/test_connection.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/tests/test_cursor.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/tests/test_exceptions.py +0 -0
- {dqlite_dbapi-0.1.2 → dqlite_dbapi-0.1.3}/tests/test_module_attributes.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dqlite-dbapi
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: PEP 249 (DB-API 2.0) compliant interface for dqlite
|
|
5
5
|
Project-URL: Homepage, https://github.com/letsdiscodev/python-dqlite-dbapi
|
|
6
6
|
Project-URL: Repository, https://github.com/letsdiscodev/python-dqlite-dbapi
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Async PEP 249-style interface for dqlite."""
|
|
2
|
+
|
|
3
|
+
from dqlitedbapi.aio.connection import AsyncConnection
|
|
4
|
+
from dqlitedbapi.aio.cursor import AsyncCursor
|
|
5
|
+
from dqlitedbapi.exceptions import (
|
|
6
|
+
DatabaseError,
|
|
7
|
+
DataError,
|
|
8
|
+
Error,
|
|
9
|
+
IntegrityError,
|
|
10
|
+
InterfaceError,
|
|
11
|
+
InternalError,
|
|
12
|
+
NotSupportedError,
|
|
13
|
+
OperationalError,
|
|
14
|
+
ProgrammingError,
|
|
15
|
+
Warning,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# PEP 249 module-level attributes (required by SQLAlchemy dialect initialization)
|
|
19
|
+
apilevel = "2.0"
|
|
20
|
+
threadsafety = 1 # Threads may share the module, but not connections
|
|
21
|
+
paramstyle = "qmark" # Question mark style: WHERE name=?
|
|
22
|
+
|
|
23
|
+
# SQLite compatibility attributes (for SQLAlchemy)
|
|
24
|
+
sqlite_version_info = (3, 35, 0)
|
|
25
|
+
sqlite_version = "3.35.0"
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
# Module attributes
|
|
29
|
+
"apilevel",
|
|
30
|
+
"threadsafety",
|
|
31
|
+
"paramstyle",
|
|
32
|
+
# Functions
|
|
33
|
+
"connect",
|
|
34
|
+
"aconnect",
|
|
35
|
+
# Classes
|
|
36
|
+
"AsyncConnection",
|
|
37
|
+
"AsyncCursor",
|
|
38
|
+
# Exceptions
|
|
39
|
+
"Warning",
|
|
40
|
+
"Error",
|
|
41
|
+
"InterfaceError",
|
|
42
|
+
"DatabaseError",
|
|
43
|
+
"DataError",
|
|
44
|
+
"OperationalError",
|
|
45
|
+
"IntegrityError",
|
|
46
|
+
"InternalError",
|
|
47
|
+
"ProgrammingError",
|
|
48
|
+
"NotSupportedError",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def connect(
|
|
53
|
+
address: str,
|
|
54
|
+
*,
|
|
55
|
+
database: str = "default",
|
|
56
|
+
timeout: float = 10.0,
|
|
57
|
+
) -> AsyncConnection:
|
|
58
|
+
"""Create a dqlite connection (connects lazily on first use).
|
|
59
|
+
|
|
60
|
+
This is a sync function that returns an AsyncConnection without
|
|
61
|
+
establishing the TCP connection yet. SQLAlchemy requires connect()
|
|
62
|
+
to be sync; the actual connection is made when the first query runs.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
address: Node address in "host:port" format
|
|
66
|
+
database: Database name to open
|
|
67
|
+
timeout: Connection timeout in seconds
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
An AsyncConnection object
|
|
71
|
+
"""
|
|
72
|
+
return AsyncConnection(address, database=database, timeout=timeout)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
async def aconnect(
|
|
76
|
+
address: str,
|
|
77
|
+
*,
|
|
78
|
+
database: str = "default",
|
|
79
|
+
timeout: float = 10.0,
|
|
80
|
+
) -> AsyncConnection:
|
|
81
|
+
"""Connect to a dqlite database asynchronously.
|
|
82
|
+
|
|
83
|
+
Unlike connect(), this awaits the TCP connection before returning.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
address: Node address in "host:port" format
|
|
87
|
+
database: Database name to open
|
|
88
|
+
timeout: Connection timeout in seconds
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
A connected AsyncConnection object
|
|
92
|
+
"""
|
|
93
|
+
conn = AsyncConnection(address, database=database, timeout=timeout)
|
|
94
|
+
await conn.connect()
|
|
95
|
+
return conn
|
|
@@ -30,24 +30,28 @@ class AsyncConnection:
|
|
|
30
30
|
self._async_conn: DqliteConnection | None = None
|
|
31
31
|
self._closed = False
|
|
32
32
|
|
|
33
|
-
async def
|
|
34
|
-
"""
|
|
33
|
+
async def _ensure_connection(self) -> DqliteConnection:
|
|
34
|
+
"""Ensure the underlying connection is established."""
|
|
35
35
|
if self._closed:
|
|
36
36
|
raise InterfaceError("Connection is closed")
|
|
37
37
|
|
|
38
|
-
if self._async_conn is
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
if self._async_conn is None:
|
|
39
|
+
self._async_conn = DqliteConnection(
|
|
40
|
+
self._address,
|
|
41
|
+
database=self._database,
|
|
42
|
+
timeout=self._timeout,
|
|
43
|
+
)
|
|
44
|
+
try:
|
|
45
|
+
await self._async_conn.connect()
|
|
46
|
+
except Exception as e:
|
|
47
|
+
self._async_conn = None
|
|
48
|
+
raise OperationalError(f"Failed to connect: {e}") from e
|
|
49
|
+
|
|
50
|
+
return self._async_conn
|
|
51
|
+
|
|
52
|
+
async def connect(self) -> None:
|
|
53
|
+
"""Establish the connection."""
|
|
54
|
+
await self._ensure_connection()
|
|
51
55
|
|
|
52
56
|
async def close(self) -> None:
|
|
53
57
|
"""Close the connection."""
|
|
@@ -72,8 +76,12 @@ class AsyncConnection:
|
|
|
72
76
|
if self._async_conn is not None:
|
|
73
77
|
await self._async_conn.execute("ROLLBACK")
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
"""Return a new AsyncCursor object.
|
|
79
|
+
def cursor(self) -> AsyncCursor:
|
|
80
|
+
"""Return a new AsyncCursor object.
|
|
81
|
+
|
|
82
|
+
This is intentionally sync — SQLAlchemy calls cursor() from
|
|
83
|
+
sync context within its greenlet-based async adapter.
|
|
84
|
+
"""
|
|
77
85
|
if self._closed:
|
|
78
86
|
raise InterfaceError("Connection is closed")
|
|
79
87
|
return AsyncCursor(self)
|
|
@@ -58,10 +58,7 @@ class AsyncCursor:
|
|
|
58
58
|
"""Execute a database operation (query or command)."""
|
|
59
59
|
self._check_closed()
|
|
60
60
|
|
|
61
|
-
conn = self._connection.
|
|
62
|
-
if conn is None:
|
|
63
|
-
raise InterfaceError("Connection is not open")
|
|
64
|
-
|
|
61
|
+
conn = await self._connection._ensure_connection()
|
|
65
62
|
params = list(parameters) if parameters else None
|
|
66
63
|
|
|
67
64
|
# Determine if this is a query that returns rows
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"""Async PEP 249-style interface for dqlite."""
|
|
2
|
-
|
|
3
|
-
from dqlitedbapi.aio.connection import AsyncConnection
|
|
4
|
-
from dqlitedbapi.aio.cursor import AsyncCursor
|
|
5
|
-
|
|
6
|
-
# PEP 249 module-level attributes (required by SQLAlchemy dialect initialization)
|
|
7
|
-
apilevel = "2.0"
|
|
8
|
-
threadsafety = 1 # Threads may share the module, but not connections
|
|
9
|
-
paramstyle = "qmark" # Question mark style: WHERE name=?
|
|
10
|
-
|
|
11
|
-
# SQLite compatibility attributes (for SQLAlchemy)
|
|
12
|
-
sqlite_version_info = (3, 35, 0)
|
|
13
|
-
sqlite_version = "3.35.0"
|
|
14
|
-
|
|
15
|
-
__all__ = [
|
|
16
|
-
"apilevel",
|
|
17
|
-
"threadsafety",
|
|
18
|
-
"paramstyle",
|
|
19
|
-
"aconnect",
|
|
20
|
-
"AsyncConnection",
|
|
21
|
-
"AsyncCursor",
|
|
22
|
-
]
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
async def aconnect(
|
|
26
|
-
address: str,
|
|
27
|
-
*,
|
|
28
|
-
database: str = "default",
|
|
29
|
-
timeout: float = 10.0,
|
|
30
|
-
) -> AsyncConnection:
|
|
31
|
-
"""Connect to a dqlite database asynchronously.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
address: Node address in "host:port" format
|
|
35
|
-
database: Database name to open
|
|
36
|
-
timeout: Connection timeout in seconds
|
|
37
|
-
|
|
38
|
-
Returns:
|
|
39
|
-
An AsyncConnection object
|
|
40
|
-
"""
|
|
41
|
-
conn = AsyncConnection(address, database=database, timeout=timeout)
|
|
42
|
-
await conn.connect()
|
|
43
|
-
return conn
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|