Skip to content

Commit ac8b2f4

Browse files
committed
Improve exception handling: Properly raise IntegrityError exceptions
... when receiving `DuplicateKeyException` errors from CrateDB, instead of the more general `ProgrammingError`.
1 parent 47ad022 commit ac8b2f4

File tree

3 files changed

+39
-2
lines changed

3 files changed

+39
-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: 24 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,18 @@ 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+
"""
318+
Verify that an `IntegrityError` is raised on duplicate key errors,
319+
instead of the more general `ProgrammingError`.
320+
"""
321+
client = Client(servers="localhost:4200")
322+
with self.assertRaises(IntegrityError) as cm:
323+
client.sql('INSERT INTO testdrive (foo) VALUES (42)')
324+
self.assertEqual(cm.exception.message,
325+
"DuplicateKeyException[A document with the same primary key exists already]")
326+
305327

306328
@patch(REQUEST, fail_sometimes)
307329
class ThreadSafeHttpClientTest(TestCase):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy