8000 Improve exception handling: Properly raise `IntegrityError` exceptions · crate/crate-python@6717def · GitHub
[go: up one dir, main page]

Skip to content

Commit 6717def

Browse files
committed
Improve exception handling: Properly raise IntegrityError exceptions
... when receiving `DuplicateKeyException` errors from CrateDB.
1 parent 47ad022 commit 6717def

File tree

3 files changed

+35
-2
lines changed

3 files changed

+35
-2
lines changed

CHANGES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Unreleased
1515
``subjectAltName`` attribute will be used.
1616
- SQLAlchemy: Improve DDL compiler to ignore foreign key and uniqueness
1717
constraints
18+
- DBAPI: Properly raise ``IntegrityError`` exceptions instead of
19+
``ProgrammingError``, when CrateDB raises a ``DuplicateKeyException``.
1820

1921
.. _urllib3 v2.0 migration guide: https://urllib3.readthedocs.io/en/latest/v2-migration-guide.html
2022
.. _urllib3 v2.0 roadmap: https://urllib3.readthedocs.io/en/stable/v2-roadmap.html

src/crate/client/http.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
BlobLocationNotFoundException,
5757
DigestNotFoundException,
5858
ProgrammingError,
59+
IntegrityError,
5960
)
6061

6162

@@ -191,6 +192,18 @@ def _ex_to_message(ex):
191192

192193

193194
def _raise_for_status(response):
195+
"""
196+
Properly raise `IntegrityError` exceptions for CrateDB's `DuplicateKeyException` errors.
197+
"""
198+
try:
199+
return _raise_for_status_real(response)
200+
except ProgrammingError as ex:
201+
if "DuplicateKeyException" in ex.message:
202+
raise IntegrityError(ex.message, error_trace=ex.error_trace) from ex
203+
raise
204+
205+
206+
def _raise_for_status_real(response):
194207
""" make sure that only crate.exceptions are raised that are defined in
195208
the DB-API specification """
196209
message = ''

src/crate/client/test_http.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@
4444
from setuptools.ssl_support import find_ca_bundle
4545

4646
from .http import Client, CrateJsonEncoder, _get_socket_opts, _remove_certs_for_non_https
47-
from .exceptions import ConnectionError, ProgrammingError
48-
47+
from .exceptions import ConnectionError, ProgrammingError, IntegrityError
4948

5049
REQUEST = 'crate.client.http.Server.request'
5150
CA_CERT_PATH = find_ca_bundle()
@@ -91,6 +90,17 @@ def bad_bulk_response():
9190
return r
9291

9392

93+
def duplicate_key_exception():
94+
r = fake_response(409, 'Conflict')
95+
r.data = json.dumps({
96+
"error": {
97+
"code": 4091,
98+
"message": "DuplicateKeyException[A document with the same primary key exists already]"
99+
}
100+
}).encode()
101+
return r
102+
103+
94104
def fail_sometimes(*args, **kwargs):
95105
if random.randint(1, 100) % 10 == 0:
96106
raise urllib3.exceptions.MaxRetryError(None, '/_sql', '')
@@ -302,6 +312,14 @@ def test_uuid_serialization(self, request):
302312
self.assertEqual(data['args'], [str(uid)])
303313
client.close()
304314

315+
@patch(REQUEST, fake_request(duplicate_key_exception()))
316+
def test_duplicate_key_error(self):
317+
client = Client(servers="localhost:4200")
318+
with self.assertRaises(IntegrityError) as cm:
319+
client.sql('INSERT INTO testdrive (foo) VALUES (42)')
320+
self.assertEqual(cm.exception.message,
321+
"DuplicateKeyException[A document with the same primary key exists already]")
322+
305323

306324
@patch(REQUEST, fail_sometimes)
307325
class ThreadSafeHttpClientTest(TestCase):

0 commit comments

Comments
 (0)
0