wherobots-python-dbapi 0.28.1__tar.gz → 0.29.0__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.
Files changed (19) hide show
  1. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/PKG-INFO +7 -2
  2. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/README.md +5 -0
  3. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/pyproject.toml +1 -1
  4. wherobots_python_dbapi-0.29.0/wherobots/db/_transport.py +57 -0
  5. wherobots_python_dbapi-0.29.0/wherobots/db/connection.py +905 -0
  6. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/wherobots/db/constants.py +4 -0
  7. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/wherobots/db/cursor.py +3 -0
  8. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/wherobots/db/driver.py +22 -0
  9. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/wherobots/db/types.py +3 -0
  10. wherobots_python_dbapi-0.28.1/wherobots/db/connection.py +0 -371
  11. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/.gitignore +0 -0
  12. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/LICENSE +0 -0
  13. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/wherobots/db/__init__.py +0 -0
  14. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/wherobots/db/errors.py +0 -0
  15. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/wherobots/db/models.py +0 -0
  16. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/wherobots/db/redaction.py +0 -0
  17. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/wherobots/db/region.py +0 -0
  18. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/wherobots/db/runtime.py +0 -0
  19. {wherobots_python_dbapi-0.28.1 → wherobots_python_dbapi-0.29.0}/wherobots/db/session_type.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: wherobots-python-dbapi
3
- Version: 0.28.1
3
+ Version: 0.29.0
4
4
  Summary: Python DB-API driver for Wherobots DB
5
5
  Project-URL: Homepage, https://github.com/wherobots/wherobots-python-dbapi-driver
6
6
  Project-URL: Tracker, https://github.com/wherobots/wherobots-python-dbapi-driver/issues
@@ -302,3 +302,8 @@ users may find useful:
302
302
  caller needs to interrupt it (e.g. on client disconnect or timeout).
303
303
  The event is checked before each HTTP request, between retry
304
304
  attempts, and before the WebSocket handshake.
305
+ * `stale_query_probe_seconds`: how long a running query may go without
306
+ any message from the SQL session before the driver asks the session
307
+ for its state again, in case the query's completion event was lost.
308
+ Repeat probes back off to at most 8 times this interval. Defaults to
309
+ 30 seconds; pass `None` to disable probing.
@@ -277,3 +277,8 @@ users may find useful:
277
277
  caller needs to interrupt it (e.g. on client disconnect or timeout).
278
278
  The event is checked before each HTTP request, between retry
279
279
  attempts, and before the WebSocket handshake.
280
+ * `stale_query_probe_seconds`: how long a running query may go without
281
+ any message from the SQL session before the driver asks the session
282
+ for its state again, in case the query's completion event was lost.
283
+ Repeat probes back off to at most 8 times this interval. Defaults to
284
+ 30 seconds; pass `None` to disable probing.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "wherobots-python-dbapi"
3
- version = "0.28.1"
3
+ version = "0.29.0"
4
4
  description = "Python DB-API driver for Wherobots DB"
5
5
  authors = [{ name = "Maxime Petazzoni", email = "max@wherobots.com" }]
6
6
  requires-python = ">=3.10, <4"
@@ -0,0 +1,57 @@
1
+ """Transport termination independent of the WebSocket protocol's send lock."""
2
+
3
+ import errno
4
+ import select
5
+ import selectors
6
+ import socket
7
+
8
+ from websockets.sync.client import ClientConnection
9
+
10
+
11
+ def abort_connection(ws: ClientConnection) -> None:
12
+ """Disable further writes and wake blocked I/O before publishing failures.
13
+
14
+ ClientConnection.close() takes the library's protocol mutex, which a
15
+ stalled sendall() may hold. Shutdown the owned socket instead; the library's
16
+ receive thread will observe EOF/error and finish protocol cleanup itself.
17
+ Already transmitted bytes may still execute remotely.
18
+ """
19
+ try:
20
+ ws.socket.shutdown(socket.SHUT_RDWR)
21
+ except OSError as exc:
22
+ if exc.errno not in (errno.ENOTCONN, errno.EBADF, errno.ECONNRESET):
23
+ raise
24
+ finally:
25
+ # Even if shutdown fails, prevent any later send on this socket object.
26
+ ws.socket.close()
27
+
28
+
29
+ def socket_writable(ws: ClientConnection) -> bool:
30
+ """Whether a small write to the transport's socket won't block right now.
31
+
32
+ For a send that must not stall the reader thread: a full send buffer
33
+ (a peer that keeps sending but stops reading) would park sendall(), which
34
+ also holds the library's protocol mutex, so even keepalive pings stall.
35
+
36
+ Never raises. Returns ``True`` (proceed, as without this check) on any
37
+ failure or for a transport without a real socket, such as a test fake:
38
+ ``False`` would silently disable the caller's sends. Uses ``poll`` (or a
39
+ selector), not ``select.select``, which fails for fds above FD_SETSIZE.
40
+ """
41
+ try:
42
+ sock = getattr(ws, "socket", None)
43
+ if not isinstance(sock, socket.socket):
44
+ return True
45
+ fd = sock.fileno()
46
+ if fd < 0:
47
+ return True # Closed: let the send itself report it.
48
+ if hasattr(select, "poll"):
49
+ poller = select.poll()
50
+ poller.register(fd, select.POLLOUT)
51
+ # POLLERR/POLLHUP count as writable: the send then fails fast.
52
+ return bool(poller.poll(0))
53
+ with selectors.DefaultSelector() as selector:
54
+ selector.register(fd, selectors.EVENT_WRITE)
55
+ return bool(selector.select(0))
56
+ except Exception:
57
+ return True