wherobots-python-dbapi 0.26.1__py3-none-any.whl → 0.27.0__py3-none-any.whl
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.
- wherobots/db/driver.py +26 -1
- {wherobots_python_dbapi-0.26.1.dist-info → wherobots_python_dbapi-0.27.0.dist-info}/METADATA +7 -1
- {wherobots_python_dbapi-0.26.1.dist-info → wherobots_python_dbapi-0.27.0.dist-info}/RECORD +5 -5
- {wherobots_python_dbapi-0.26.1.dist-info → wherobots_python_dbapi-0.27.0.dist-info}/WHEEL +0 -0
- {wherobots_python_dbapi-0.26.1.dist-info → wherobots_python_dbapi-0.27.0.dist-info}/licenses/LICENSE +0 -0
wherobots/db/driver.py
CHANGED
|
@@ -11,6 +11,7 @@ from packaging.version import Version
|
|
|
11
11
|
import platform
|
|
12
12
|
import requests
|
|
13
13
|
import tenacity
|
|
14
|
+
import threading
|
|
14
15
|
from typing import Final, Union, Dict
|
|
15
16
|
import urllib.parse
|
|
16
17
|
import websockets.exceptions
|
|
@@ -51,6 +52,9 @@ paramstyle: Final[str] = PARAM_STYLE
|
|
|
51
52
|
# This follows the industry-standard set used by urllib3.util.Retry's status_forcelist.
|
|
52
53
|
TRANSIENT_HTTP_STATUS_CODES = {429, 502, 503, 504}
|
|
53
54
|
|
|
55
|
+
# Default timeout for individual HTTP requests (connect + read), in seconds.
|
|
56
|
+
DEFAULT_HTTP_TIMEOUT = 30
|
|
57
|
+
|
|
54
58
|
|
|
55
59
|
def gen_user_agent_header():
|
|
56
60
|
try:
|
|
@@ -79,6 +83,7 @@ def connect(
|
|
|
79
83
|
results_format: Union[ResultsFormat, None] = None,
|
|
80
84
|
data_compression: Union[DataCompression, None] = None,
|
|
81
85
|
geometry_representation: Union[GeometryRepresentation, None] = None,
|
|
86
|
+
cancel_event: Union[threading.Event, None] = None,
|
|
82
87
|
) -> Connection:
|
|
83
88
|
if not token and not api_key:
|
|
84
89
|
raise ValueError("At least one of `token` or `api_key` is required")
|
|
@@ -109,6 +114,8 @@ def connect(
|
|
|
109
114
|
if not host.startswith("http:"):
|
|
110
115
|
host = f"https://{host}"
|
|
111
116
|
|
|
117
|
+
_check_cancelled(cancel_event)
|
|
118
|
+
|
|
112
119
|
try:
|
|
113
120
|
resp = requests.post(
|
|
114
121
|
url=f"{host}/sql/session",
|
|
@@ -120,6 +127,7 @@ def connect(
|
|
|
120
127
|
"sessionType": session_type.value,
|
|
121
128
|
},
|
|
122
129
|
headers=headers,
|
|
130
|
+
timeout=DEFAULT_HTTP_TIMEOUT,
|
|
123
131
|
)
|
|
124
132
|
resp.raise_for_status()
|
|
125
133
|
except requests.HTTPError as e:
|
|
@@ -149,10 +157,12 @@ def connect(
|
|
|
149
157
|
)
|
|
150
158
|
| tenacity.retry_if_exception_type(tenacity.TryAgain)
|
|
151
159
|
),
|
|
160
|
+
before_sleep=lambda _: _check_cancelled(cancel_event),
|
|
152
161
|
reraise=True,
|
|
153
162
|
)
|
|
154
163
|
def get_session_uri() -> str:
|
|
155
|
-
|
|
164
|
+
_check_cancelled(cancel_event)
|
|
165
|
+
r = requests.get(session_id_url, headers=headers, timeout=DEFAULT_HTTP_TIMEOUT)
|
|
156
166
|
r.raise_for_status()
|
|
157
167
|
payload = r.json()
|
|
158
168
|
status = AppStatus(payload.get("status"))
|
|
@@ -169,6 +179,8 @@ def connect(
|
|
|
169
179
|
logging.info("Getting SQL session status from %s ...", session_id_url)
|
|
170
180
|
session_uri = get_session_uri()
|
|
171
181
|
logging.debug("SQL session URI from app status: %s", session_uri)
|
|
182
|
+
except InterfaceError:
|
|
183
|
+
raise
|
|
172
184
|
except Exception as e:
|
|
173
185
|
raise InterfaceError("Could not acquire SQL session!", e)
|
|
174
186
|
|
|
@@ -179,9 +191,16 @@ def connect(
|
|
|
179
191
|
results_format=results_format,
|
|
180
192
|
data_compression=data_compression,
|
|
181
193
|
geometry_representation=geometry_representation,
|
|
194
|
+
cancel_event=cancel_event,
|
|
182
195
|
)
|
|
183
196
|
|
|
184
197
|
|
|
198
|
+
def _check_cancelled(cancel_event: Union[threading.Event, None]) -> None:
|
|
199
|
+
"""Raise InterfaceError if the cancel event is set."""
|
|
200
|
+
if cancel_event is not None and cancel_event.is_set():
|
|
201
|
+
raise InterfaceError("Connection cancelled by caller")
|
|
202
|
+
|
|
203
|
+
|
|
185
204
|
def http_to_ws(uri: str) -> str:
|
|
186
205
|
"""Converts an HTTP URI to a WebSocket URI."""
|
|
187
206
|
parsed = urllib.parse.urlparse(uri)
|
|
@@ -199,6 +218,7 @@ def connect_direct(
|
|
|
199
218
|
results_format: Union[ResultsFormat, None] = None,
|
|
200
219
|
data_compression: Union[DataCompression, None] = None,
|
|
201
220
|
geometry_representation: Union[GeometryRepresentation, None] = None,
|
|
221
|
+
cancel_event: Union[threading.Event, None] = None,
|
|
202
222
|
) -> Connection:
|
|
203
223
|
uri_with_protocol = f"{uri}/{protocol}"
|
|
204
224
|
ssl_context = ssl.create_default_context()
|
|
@@ -215,19 +235,24 @@ def connect_direct(
|
|
|
215
235
|
websockets.exceptions.InvalidHandshake,
|
|
216
236
|
)
|
|
217
237
|
),
|
|
238
|
+
before_sleep=lambda _: _check_cancelled(cancel_event),
|
|
218
239
|
reraise=True,
|
|
219
240
|
)
|
|
220
241
|
def ws_connect() -> websockets.sync.client.ClientConnection:
|
|
242
|
+
_check_cancelled(cancel_event)
|
|
221
243
|
logging.info("Connecting to SQL session at %s ...", uri_with_protocol)
|
|
222
244
|
return websockets.sync.client.connect(
|
|
223
245
|
uri=uri_with_protocol,
|
|
224
246
|
additional_headers=headers,
|
|
225
247
|
max_size=MAX_MESSAGE_SIZE,
|
|
248
|
+
open_timeout=DEFAULT_HTTP_TIMEOUT,
|
|
226
249
|
ssl=ssl_context,
|
|
227
250
|
)
|
|
228
251
|
|
|
229
252
|
try:
|
|
230
253
|
ws = ws_connect()
|
|
254
|
+
except InterfaceError:
|
|
255
|
+
raise
|
|
231
256
|
except Exception as e:
|
|
232
257
|
raise InterfaceError("Failed to connect to SQL session!") from e
|
|
233
258
|
|
{wherobots_python_dbapi-0.26.1.dist-info → wherobots_python_dbapi-0.27.0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wherobots-python-dbapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.27.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
|
|
@@ -285,3 +285,9 @@ users may find useful:
|
|
|
285
285
|
your expected time between queries and effectively get a continuously
|
|
286
286
|
running SQL session runtime without any complex connection management
|
|
287
287
|
in your application.
|
|
288
|
+
* `cancel_event`: a `threading.Event` that, when set, causes the
|
|
289
|
+
connection attempt to abort promptly with an `InterfaceError`. This
|
|
290
|
+
is useful when `connect()` is running in a background thread and the
|
|
291
|
+
caller needs to interrupt it (e.g. on client disconnect or timeout).
|
|
292
|
+
The event is checked before each HTTP request, between retry
|
|
293
|
+
attempts, and before the WebSocket handshake.
|
|
@@ -3,14 +3,14 @@ wherobots/db/__init__.py,sha256=HN_uGOUMor80GB3rZIqnPcYWDAia7QAC-y9HfGKnegs,744
|
|
|
3
3
|
wherobots/db/connection.py,sha256=BWQwVzFgujEwPKvhDePM9q45M2opCk6Jq998L0ekMyY,12795
|
|
4
4
|
wherobots/db/constants.py,sha256=qV-6CmOya7-f-DoRMzcDzlhcmV5PkLCcqG5TFIsxQ7o,744
|
|
5
5
|
wherobots/db/cursor.py,sha256=Z0rNdhJ985IP9XnZpjrCzvM0OqDFVgCNfJn8lrbijAo,6809
|
|
6
|
-
wherobots/db/driver.py,sha256=
|
|
6
|
+
wherobots/db/driver.py,sha256=Hvldyos2yCMoshq80PFI-4rYhVGPV2SL5OioTuY7PmE,8966
|
|
7
7
|
wherobots/db/errors.py,sha256=G8a-DB6pgB0pUld59Wyq8PuywL-JWxGJfvrr-g8BPuU,310
|
|
8
8
|
wherobots/db/models.py,sha256=uk0EqZMH_RFkQusSw2AvyFivGvGJBu_WYP8FHa6JJGM,4178
|
|
9
9
|
wherobots/db/region.py,sha256=GoFzazvgOjE1kVVT1QKAsRK88c_1XSAebR3ME4foSlQ,400
|
|
10
10
|
wherobots/db/runtime.py,sha256=eAR1oJEtssgkp-IRPTLOrlPI-_5SM_ASw6T6hQ_qF4I,985
|
|
11
11
|
wherobots/db/session_type.py,sha256=jZNwCl0nxvY-0reIn8RR_-fIYSSvIcaGx_4pRc71Lww,137
|
|
12
12
|
wherobots/db/types.py,sha256=WXKT_gbdQCH2_yXD_FECk0BpB7yfNWOLewCfax0U_Lk,2516
|
|
13
|
-
wherobots_python_dbapi-0.
|
|
14
|
-
wherobots_python_dbapi-0.
|
|
15
|
-
wherobots_python_dbapi-0.
|
|
16
|
-
wherobots_python_dbapi-0.
|
|
13
|
+
wherobots_python_dbapi-0.27.0.dist-info/METADATA,sha256=FMCBp3yiCPb_d0AqxVkMmRqtDG5akWaktCfcJ5Uh4W0,10726
|
|
14
|
+
wherobots_python_dbapi-0.27.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
15
|
+
wherobots_python_dbapi-0.27.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
16
|
+
wherobots_python_dbapi-0.27.0.dist-info/RECORD,,
|
|
File without changes
|
{wherobots_python_dbapi-0.26.1.dist-info → wherobots_python_dbapi-0.27.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|