Skip to content

Commit 492e12b

Browse files
committed
Properly populate exceptions from bulk operations
1 parent e5b605d commit 492e12b

File tree

5 files changed

+92
-72
lines changed

5 files changed

+92
-72
lines changed

arango/collection.py

+35-60
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
IndexLoadError,
3838
)
3939
from arango.request import Request
40-
from arango.response import Response
4140
from arango.utils import (
4241
get_doc_id,
4342
is_none_or_int,
@@ -1648,20 +1647,13 @@ def response_handler(resp):
16481647
return True
16491648

16501649
results = []
1651-
for result in resp.body:
1652-
if '_id' in result:
1653-
if '_oldRev' in result:
1654-
result['_old_rev'] = result.pop('_oldRev')
1655-
results.append(result)
1650+
for body in resp.body:
1651+
if '_id' in body:
1652+
if '_oldRev' in body:
1653+
body['_old_rev'] = body.pop('_oldRev')
1654+
results.append(body)
16561655
else:
1657-
sub_resp = Response(
1658-
method=resp.method,
1659-
url=resp.url,
1660-
headers=resp.headers,
1661-
status_code=resp.status_code,
1662-
status_text=resp.status_text,
1663-
raw_body=result
1664-
)
1656+
sub_resp = self._conn.build_error_response(resp, body)
16651657
results.append(DocumentInsertError(sub_resp, request))
16661658

16671659
return results
@@ -1814,23 +1806,17 @@ def response_handler(resp):
18141806
return True
18151807

18161808
results = []
1817-
for result in resp.body:
1818-
if '_id' not in result:
1819-
sub_resp = Response(
1820-
method='patch',
1821-
url=resp.url,
1822-
headers=resp.headers,
1823-
status_code=resp.status_code,
1824-
status_text=resp.status_text,
1825-
raw_body=result,
1826-
)
1827-
if result['errorNum'] == 1200:
1828-
result = DocumentRevisionError(sub_resp, request)
1829-
else: # pragma: no cover
1830-
result = DocumentUpdateError(sub_resp, request)
1809+
for body in resp.body:
1810+
if '_id' in body:
1811+
body['_old_rev'] = body.pop('_oldRev')
1812+
results.append(body)
18311813
else:
1832-
result['_old_rev'] = result.pop('_oldRev')
1833-
results.append(result)
1814+
sub_resp = self._conn.build_error_response(resp, body)
1815+
if sub_resp.error_code == 1200:
1816+
error = DocumentRevisionError(sub_resp, request)
1817+
else: # pragma: no cover
1818+
error = DocumentUpdateError(sub_resp, request)
1819+
results.append(error)
18341820

18351821
return results
18361822

@@ -2019,23 +2005,17 @@ def response_handler(resp):
20192005
return True
20202006

20212007
results = []
2022-
for result in resp.body:
2023-
if '_id' not in result:
2024-
sub_resp = Response(
2025-
method=resp.method,
2026-
url=resp.url,
2027-
headers=resp.headers,
2028-
status_code=resp.status_code,
2029-
status_text=resp.status_text,
2030-
raw_body=result
2031-
)
2032-
if result['errorNum'] == 1200:
2033-
result = DocumentRevisionError(sub_resp, request)
2034-
else: # pragma: no cover
2035-
result = DocumentReplaceError(sub_resp, request)
2008+
for body in resp.body:
2009+
if '_id' in body:
2010+
body['_old_rev'] = body.pop('_oldRev')
2011+
results.append(body)
20362012
else:
2037-
result['_old_rev'] = result.pop('_oldRev')
2038-
results.append(result)
2013+
sub_resp = self._conn.build_error_response(resp, body)
2014+
if sub_resp.error_code == 1200:
2015+
error = DocumentRevisionError(sub_resp, request)
2016+
else: # pragma: no cover
2017+
error = DocumentReplaceError(sub_resp, request)
2018+
results.append(error)
20392019

20402020
return results
20412021

@@ -2212,21 +2192,16 @@ def response_handler(resp):
22122192
return True
22132193

22142194
results = []
2215-
for result in resp.body:
2216-
if '_id' not in result:
2217-
sub_resp = Response(
2218-
method=resp.method,
2219-
url=resp.url,
2220-
headers=resp.headers,
2221-
status_code=resp.status_code,
2222-
status_text=resp.status_text,
2223-
raw_body=result
2224-
)
2225-
if result['errorNum'] == 1200:
2226-
result = DocumentRevisionError(sub_resp, request)
2195+
for body in resp.body:
2196+
if '_id' in body:
2197+
results.append(body)
2198+
else:
2199+
sub_resp = self._conn.build_error_response(resp, body)
2200+
if sub_resp.error_code == 1200:
2201+
error = DocumentRevisionError(sub_resp, request)
22272202
else:
2228-
result = DocumentDeleteError(sub_resp, request)
2229-
results.append(result)
2203+
error = DocumentDeleteError(sub_resp, request)
2204+
results.append(error)
22302205

22312206
return results
22322207

arango/connection.py

+25
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from six import string_types
44

55
from arango.exceptions import ServerConnectionError
6+
from arango.response import Response
67

78
__all__ = ['Connection']
89

@@ -105,6 +106,30 @@ def prep_response(self, response):
105106
response.is_success = http_ok and response.error_code is None
106107
return response
107108

109+
def build_error_response(self, parent_response, body):
110+
"""Build and return a bulk error response.
111+
112+
:param parent_response: Parent response.
113+
:type parent_response: arango.response.Response
114+
:param body: Error response body.
115+
:type body: dict
116+
:return: Child bulk error response.
117+
:rtype: arango.response.Response
118+
"""
119+
response = Response(
120+
method=parent_response.method,
121+
url=parent_response.url,
122+
headers=parent_response.headers,
123+
status_code=parent_response.status_code,
124+
status_text=parent_response.status_text,
125+
raw_body=self.serialize(body),
126+
)
127+
response.body = body
128+
response.error_code = body['errorNum']
129+
response.error_message = body['errorMessage']
130+
response.is_success = False
131+
return response
132+
108133
def send_request(self, request):
109134
"""Send an HTTP request to ArangoDB server.
110135

arango/exceptions.py

-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ def __init__(self, resp, request, msg=None):
8080
self.http_code = resp.status_code
8181
self.http_headers = resp.headers
8282

83-
8483
##################
8584
# AQL Exceptions #
8685
##################

arango/version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '5.0.0'
1+
__version__ = '5.1.0'

tests/test_document.py

+31-10
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,12 @@ def test_document_insert_many(col, bad_col, docs):
189189

190190
# Test insert_many duplicate documents
191191
results = col.insert_many(docs, return_new=False)
192-
for result, doc in zip(results, docs):
193-
assert isinstance(result, DocumentInsertError)
192+
for error, doc in zip(results, docs):
193+
assert isinstance(error, DocumentInsertError)
194+
assert error.error_code in {1210}
195+
assert 'unique constraint violated' in error.error_message
196+
assert error.http_code == 202
197+
assert '[HTTP 202][ERR 1210]' in error.message
194198

195199
# Test insert_many with overwrite and return_old set to True
196200
results = col.insert_many(docs, overwrite=True, return_old=True)
@@ -455,8 +459,13 @@ def test_document_update_many(col, bad_col, docs):
455459
doc['val'] = 5
456460
doc['_rev'] = old_revs[doc['_key']] + '0'
457461
results = col.update_many(docs, check_rev=True)
458-
for result, doc_key in zip(results, doc_keys):
459-
assert isinstance(result, DocumentRevisionError)
462+
for error, doc_key in zip(results, doc_keys):
463+
assert isinstance(error, DocumentRevisionError)
464+
assert error.error_code in {1200}
465+
assert 'conflict' in error.error_message
466+
assert error.http_code == 202
467+
assert '[HTTP 202][ERR 1200]' in error.message
468+
460469
for doc in col:
461470
assert doc['val'] == 4
462471

@@ -729,8 +738,12 @@ def test_document_replace_many(col, bad_col, docs):
729738
doc.pop('baz')
730739
doc['_rev'] = old_revs[doc['_key']] + '0'
731740
results = col.replace_many(docs, check_rev=True)
732-
for result, doc_key in zip(results, doc_keys):
733-
assert isinstance(result, DocumentRevisionError)
741+
for error, doc_key in zip(results, doc_keys):
742+
assert isinstance(error, DocumentRevisionError)
743+
assert error.error_code in {1200}
744+
assert 'conflict' in error.error_message
745+
assert error.http_code == 202
746+
assert '[HTTP 202][ERR 1200]' in error.message
734747
for doc in col:
735748
assert 'foo' not in doc
736749
assert doc['baz'] == 4
@@ -957,8 +970,12 @@ def test_document_delete_many(col, bad_col, docs):
957970
for doc in docs:
958971
doc['_rev'] = old_revs[doc['_key']] + '0'
959972
results = col.delete_many(docs, check_rev=True)
960-
for result, doc in zip(results, docs):
961-
assert isinstance(result, DocumentRevisionError)
973+
for error, doc in zip(results, docs):
974+
assert isinstance(error, DocumentRevisionError)
975+
assert error.error_code in {1200}
976+
assert 'conflict' in error.error_message
977+
assert error.http_code == 202
978+
assert '[HTTP 202][ERR 1200]' in error.message
962979
assert len(col) == 6
963980

964981
# Test delete_many (documents) with missing documents
@@ -968,8 +985,12 @@ def test_document_delete_many(col, bad_col, docs):
968985
{'_key': generate_doc_key()},
969986
{'_key': generate_doc_key()}
970987
])
971-
for result, doc in zip(results, docs):
972-
assert isinstance(result, DocumentDeleteError)
988+
for error, doc in zip(results, docs):
989+
assert isinstance(error, DocumentDeleteError)
990+
assert error.error_code in {1202}
991+
assert 'document not found' in error.error_message
992+
assert error.http_code == 202
993+
assert '[HTTP 202][ERR 1202]' in error.message
973994
assert len(col) == 0
974995

975996
# Test delete_many with bad database

0 commit comments

Comments
 (0)