Skip to content

Commit 52392e4

Browse files
authored
Merge pull request #17 from joowani/dev
Add more methods for async API and improve tests and documentation
2 parents 2488762 + 9cb6d9d commit 52392e4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1566
-490
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*.egg-info
55
*build/
66
*dist/
7+
*htmlcov/
78
*.coverage
8-
.coveragerc
99
.cache/
1010
tests/__pycache__/

README.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ Features
3838

3939
- Clean, Pythonic interface
4040
- Lightweight
41-
- 95%+ API coverage
41+
- 95%+ ArangoDB REST API coverage
4242

4343
Compatibility
4444
=============
4545

4646
- Python versions 2.7.x, 3.4.x and 3.5.x are supported
4747
- Latest version of python-arango (3.x) supports ArangoDB 3.x only
48-
- Older versions of python-arango (2.x) support ArangoDB 2.x only
48+
- Older versions of python-arango support ArangoDB 1.x ~ 2.x only
4949

5050
Installation
5151
============
@@ -82,7 +82,7 @@ Here is a simple usage example:
8282
# Initialize the client for ArangoDB
8383
client = ArangoClient(
8484
protocol='http',
85-
host="localhost",
85+
host='localhost',
8686
port=8529,
8787
username='root',
8888
password='',

arango/aql.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
AQLQueryExecuteError,
1010
AQLFunctionCreateError,
1111
AQLFunctionDeleteError,
12-
AQLFunctionsListError,
12+
AQLFunctionListError,
1313
AQLCacheClearError,
1414
AQLCacheConfigureError,
15-
AQLCacheGetPropertiesError
15+
AQLCachePropertiesError
1616
)
1717
from arango.request import Request
1818

@@ -168,14 +168,14 @@ def functions(self):
168168
169169
:returns: a mapping of AQL function names to its javascript code
170170
:rtype: dict
171-
:raises arango.exceptions.AQLFunctionsListError: if the AQL functions
171+
:raises arango.exceptions.AQLFunctionListError: if the AQL functions
172172
cannot be retrieved
173173
"""
174174
request = Request(method='get', endpoint='/_api/aqlfunction')
175175

176176
def handler(res):
177177
if res.status_code not in HTTP_OK:
178-
raise AQLFunctionsListError(res)
178+
raise AQLFunctionListError(res)
179179
body = res.body or {}
180180
return {func['name']: func['code'] for func in map(dict, body)}
181181

@@ -259,7 +259,7 @@ def properties(self):
259259
260260
:returns: the cache properties
261261
:rtype: dict
262-
:raises arango.exceptions.AQLCacheGetPropertiesError: if the cache
262+
:raises arango.exceptions.AQLCachePropertiesError: if the cache
263263
properties cannot be retrieved
264264
"""
265265
request = Request(
@@ -269,7 +269,7 @@ def properties(self):
269269

270270
def handler(res):
271271
if res.status_code not in HTTP_OK:
272-
raise AQLCacheGetPropertiesError(res)
272+
raise AQLCachePropertiesError(res)
273273
return {'mode': res.body['mode'], 'limit': res.body['maxResults']}
274274

275275
return request, handler

arango/async.py

+34-67
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,9 @@
55
from arango.utils import HTTP_OK
66
from arango.exceptions import (
77
AsyncExecuteError,
8-
AsyncJobInvalidError,
9-
AsyncJobNotDoneError,
10-
AsyncJobNotFoundError,
118
AsyncJobCancelError,
12-
AsyncJobGetStatusError,
13-
AsyncJobGetResultError,
9+
AsyncJobStatusError,
10+
AsyncJobResultError,
1411
AsyncJobClearError
1512
)
1613
from arango.graph import Graph
@@ -39,14 +36,15 @@ def __init__(self, connection, return_result=True):
3936
username=connection.username,
4037
password=connection.password,
4138
http_client=connection.http_client,
42-
database=connection.database
39+
database=connection.database,
40+
enable_logging=connection.has_logging
4341
)
4442
self._return_result = return_result
4543
self._aql = AQL(self)
4644
self._type = 'async'
4745

4846
def __repr__(self):
49-
return '<ArangoDB asynchronous request>'
47+
return '<ArangoDB asynchronous execution>'
5048

5149
def handle_request(self, request, handler):
5250
"""Handle the incoming request and response handler.
@@ -57,11 +55,13 @@ def handle_request(self, request, handler):
5755
:type handler: callable
5856
:returns: the async job or None
5957
:rtype: arango.async.AsyncJob
58+
:raises arango.exceptions.AsyncExecuteError: if the async request
59+
cannot be executed
6060
"""
6161
if self._return_result:
6262
request.headers['x-arango-async'] = 'store'
6363
else:
64-
request.headers['x-arango-async'] = True
64+
request.headers['x-arango-async'] = 'true'
6565

6666
res = getattr(self, request.method)(**request.kwargs)
6767
if res.status_code not in HTTP_OK:
@@ -145,66 +145,48 @@ def status(self):
145145
"""Return the status of the async job from the server.
146146
147147
:returns: the status of the async job, which can be ``"pending"`` (the
148-
job is still in the queue), ``"done"`` (the job completed or raised
148+
job is still in the queue), ``"done"`` (the job finished or raised
149149
an exception)
150150
:rtype: str
151-
:raises arango.exceptions.AsyncJobInvalidError: if the async job is
152-
not valid
153-
:raises arango.exceptions.AsyncJobNotFoundError: if the async job
154-
cannot be found in the server
155-
:raises arango.exceptions.AsyncJobGetStatusError: if the status of the
151+
:raises arango.exceptions.AsyncJobStatusError: if the status of the
156152
async job cannot be retrieved from the server
157153
"""
158-
res = self._conn.get('/_api/job/{}'.format(self._id))
154+
res = self._conn.get('/_api/job/{}'.format(self.id))
159155
if res.status_code == 204:
160156
return 'pending'
161157
elif res.status_code in HTTP_OK:
162158
return 'done'
163-
elif res.status_code == 400:
164-
raise AsyncJobInvalidError(res)
165159
elif res.status_code == 404:
166-
raise AsyncJobNotFoundError(res)
160+
raise AsyncJobStatusError(res, 'Job {} missing'.format(self.id))
167161
else:
168-
raise AsyncJobGetStatusError(res)
162+
raise AsyncJobStatusError(res)
169163

170164
def result(self):
171165
"""Return the result of the async job if available.
172166
173167
:returns: the result or the exception from the async job
174168
:rtype: object
175-
:raises arango.exceptions.AsyncJobInvalidError: if the async job is
176-
not valid
177-
:raises arango.exceptions.AsyncJobNotFoundError: if the async job
178-
cannot be found in the server
179-
:raises arango.exceptions.AsyncJobNotDoneError: if the async job is
180-
still pending in the queue
181-
:raises arango.exceptions.AsyncJobGetResultError: if the result of the
169+
:raises arango.exceptions.AsyncJobResultError: if the result of the
182170
async job cannot be retrieved from the server
183171
184172
.. note::
185173
An async job result will automatically be cleared from the server
186174
once fetched and will *not* be available in subsequent calls.
187175
"""
188-
_id = self._id
189-
res = self._conn.put('/_api/job/{}'.format(_id))
190-
if (
191-
res.status_code == 404 and
192-
res.error_code == 404 and
193-
res.error_message == 'not found'
194-
):
195-
raise AsyncJobNotFoundError(res, 'Job {} not found'.format(_id))
196-
elif res.body is not None:
176+
res = self._conn.put('/_api/job/{}'.format(self._id))
177+
if 'X-Arango-Async-Id' in res.headers:
197178
try:
198179
result = self._handler(res)
199180
except Exception as error:
200181
return error
201182
else:
202183
return result
203184
elif res.status_code == 204:
204-
raise AsyncJobNotDoneError(res, 'Job {} pending'.format(_id))
205-
elif res.status_code == 400:
206-
raise AsyncJobInvalidError(res, 'Job {} invalid'.format(_id))
207-
raise AsyncJobGetResultError(res, 'Failed to query job {}'.format(_id))
185+
raise AsyncJobResultError(res, 'Job {} not done'.format(self._id))
186+
elif res.status_code == 404:
187+
raise AsyncJobResultError(res, 'Job {} missing'.format(self._id))
188+
else:
189+
raise AsyncJobResultError(res)
208190

209191
def cancel(self, ignore_missing=False):
210192
"""Cancel the async job if it is still pending.
@@ -214,55 +196,40 @@ def cancel(self, ignore_missing=False):
214196
:returns: ``True`` if the job was cancelled successfully, ``False`` if
215197
the job was not found but **ignore_missing** was set to ``True``
216198
:rtype: bool
217-
:raises arango.exceptions.AsyncJobInvalidError: if the async job is
218-
not valid
219-
:raises arango.exceptions.AsyncJobNotFoundError: if the async job
220-
cannot be found in the server
221199
:raises arango.exceptions.AsyncJobCancelError: if the async job cannot
222200
be cancelled
223201
224202
.. note::
225-
An async job cannot be cancelled once it is taken out of the queue.
203+
An async job cannot be cancelled once it is taken out of the queue
204+
(i.e. started, finished or cancelled).
226205
"""
227-
_id = self._id
228-
res = self._conn.put('/_api/job/{}/cancel'.format(_id))
206+
res = self._conn.put('/_api/job/{}/cancel'.format(self._id))
229207
if res.status_code == 200:
230208
return True
231-
elif res.status_code == 400:
232-
raise AsyncJobInvalidError(res, 'Job {} invalid'.format(_id))
233209
elif res.status_code == 404:
234210
if ignore_missing:
235211
return False
236-
raise AsyncJobNotFoundError(res, 'Job {} not found'.format(_id))
237-
raise AsyncJobCancelError(res, 'Failed to cancel job {}'.format(_id))
212+
raise AsyncJobCancelError(res, 'Job {} missing'.format(self._id))
213+
else:
214+
raise AsyncJobCancelError(res)
238215

239216
def clear(self, ignore_missing=False):
240-
"""Clear the result of the job from the server if available.
241-
242-
If the result is deleted successfully, boolean True is returned. If
243-
the job was not found but ``ignore_missing`` was set, boolean False
244-
is returned.
217+
"""Delete the result of the job from the server.
245218
246219
:param ignore_missing: ignore missing async jobs
247220
:type ignore_missing: bool
248221
:returns: ``True`` if the result was deleted successfully, ``False``
249222
if the job was not found but **ignore_missing** was set to ``True``
250223
:rtype: bool
251-
:raises arango.exceptions.AsyncJobInvalidError: if the async job is
252-
not valid
253-
:raises arango.exceptions.AsyncJobNotFoundError: if the async job
254-
cannot be found in the server
255-
:raises arango.exceptions.AsyncJobClearError: if the result of
256-
the async job cannot be removed from the server
224+
:raises arango.exceptions.AsyncJobClearError: if the result of the
225+
async job cannot be delete from the server
257226
"""
258-
_id = self._id
259-
res = self._conn.delete('/_api/job/{}'.format(_id))
227+
res = self._conn.delete('/_api/job/{}'.format(self._id))
260228
if res.status_code in HTTP_OK:
261229
return True
262-
elif res.status_code == 400:
263-
raise AsyncJobInvalidError(res, 'Job {} invalid'.format(_id))
264230
elif res.status_code == 404:
265231
if ignore_missing:
266232
return False
267-
raise AsyncJobNotFoundError(res, 'Job {} not found'.format(_id))
268-
raise AsyncJobClearError(res, 'Failed to clear job {}'.format(_id))
233+
raise AsyncJobClearError(res, 'Job {} missing'.format(self._id))
234+
else:
235+
raise AsyncJobClearError(res)

arango/batch.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ def __init__(self, connection, return_result=True, commit_on_error=False):
3838
username=connection.username,
3939
password=connection.password,
4040
http_client=connection.http_client,
41-
database=connection.database
41+
database=connection.database,
42+
enable_logging=connection.has_logging
4243
)
4344
self._id = uuid4()
4445
self._return_result = return_result
@@ -50,7 +51,7 @@ def __init__(self, connection, return_result=True, commit_on_error=False):
5051
self._type = 'batch'
5152

5253
def __repr__(self):
53-
return '<ArangoDB batch request {}>'.format(self._id)
54+
return '<ArangoDB batch execution {}>'.format(self._id)
5455

5556
def __enter__(self):
5657
return self

0 commit comments

Comments
 (0)