python-arango-async 0.0.1__tar.gz → 0.0.3__tar.gz
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.
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/.github/workflows/pypi.yaml +5 -1
- {python_arango_async-0.0.1/python_arango_async.egg-info → python_arango_async-0.0.3}/PKG-INFO +7 -29
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/README.md +3 -3
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/aql.py +5 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/client.py +3 -1
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/collection.py +27 -2
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/connection.py +3 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/database.py +0 -4
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/http.py +22 -0
- python_arango_async-0.0.3/arangoasync/version.py +1 -0
- python_arango_async-0.0.3/docs/aql.rst +171 -0
- python_arango_async-0.0.3/docs/async.rst +148 -0
- python_arango_async-0.0.3/docs/authentication.rst +117 -0
- python_arango_async-0.0.3/docs/certificates.rst +110 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/docs/collection.rst +8 -1
- python_arango_async-0.0.3/docs/compression.rst +56 -0
- python_arango_async-0.0.3/docs/cursor.rst +217 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/docs/database.rst +2 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/docs/document.rst +16 -14
- python_arango_async-0.0.3/docs/errno.rst +22 -0
- python_arango_async-0.0.3/docs/errors.rst +119 -0
- python_arango_async-0.0.3/docs/helpers.rst +88 -0
- python_arango_async-0.0.3/docs/http.rst +136 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/docs/index.rst +18 -8
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/docs/indexes.rst +6 -4
- python_arango_async-0.0.3/docs/logging.rst +30 -0
- python_arango_async-0.0.3/docs/migration.rst +94 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/docs/overview.rst +23 -0
- python_arango_async-0.0.3/docs/serialization.rst +183 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/docs/specs.rst +0 -6
- python_arango_async-0.0.3/docs/transaction.rst +81 -0
- python_arango_async-0.0.3/docs/user.rst +93 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/pyproject.toml +4 -4
- {python_arango_async-0.0.1 → python_arango_async-0.0.3/python_arango_async.egg-info}/PKG-INFO +7 -29
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/python_arango_async.egg-info/SOURCES.txt +9 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_async.py +1 -1
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_client.py +9 -9
- python_arango_async-0.0.1/arangoasync/version.py +0 -1
- python_arango_async-0.0.1/docs/aql.rst +0 -10
- python_arango_async-0.0.1/docs/async.rst +0 -6
- python_arango_async-0.0.1/docs/errno.rst +0 -19
- python_arango_async-0.0.1/docs/errors.rst +0 -20
- python_arango_async-0.0.1/docs/transaction.rst +0 -5
- python_arango_async-0.0.1/docs/user.rst +0 -5
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/.circleci/config.yml +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/.github/workflows/codeql.yaml +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/.github/workflows/docs.yaml +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/.gitignore +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/.pre-commit-config.yaml +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/.readthedocs.yaml +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/CONTRIBUTING.md +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/LICENSE +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/__init__.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/auth.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/compression.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/cursor.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/errno.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/exceptions.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/executor.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/job.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/logger.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/request.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/resolver.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/response.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/result.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/serialization.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/arangoasync/typings.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/docs/conf.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/docs/static/logo.png +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/python_arango_async.egg-info/dependency_links.txt +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/python_arango_async.egg-info/requires.txt +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/python_arango_async.egg-info/top_level.txt +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/setup.cfg +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/setup.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/starter.sh +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/__init__.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/conftest.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/helpers.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/static/cluster-3.11.conf +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/static/cluster-3.12.conf +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/static/keyfile +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/static/single-3.11.conf +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/static/single-3.12.conf +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_aql.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_collection.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_compression.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_connection.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_cursor.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_database.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_document.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_http.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_resolver.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_transaction.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_typings.py +0 -0
- {python_arango_async-0.0.1 → python_arango_async-0.0.3}/tests/test_user.py +0 -0
{python_arango_async-0.0.1/python_arango_async.egg-info → python_arango_async-0.0.3}/PKG-INFO
RENAMED
|
@@ -1,45 +1,23 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-arango-async
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: Async Python Driver for ArangoDB
|
|
5
5
|
Author-email: Alexandru Petenchea <alexandru.petenchea@arangodb.com>, Anthony Mahanna <anthony.mahanna@arangodb.com>
|
|
6
6
|
Maintainer-email: Alexandru Petenchea <alexandru.petenchea@arangodb.com>, Anthony Mahanna <anthony.mahanna@arangodb.com>
|
|
7
|
-
License: MIT
|
|
8
|
-
|
|
9
|
-
Copyright (c) 2024 ArangoDB
|
|
10
|
-
|
|
11
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
-
in the Software without restriction, including without limitation the rights
|
|
14
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
-
furnished to do so, subject to the following conditions:
|
|
17
|
-
|
|
18
|
-
The above copyright notice and this permission notice shall be included in all
|
|
19
|
-
copies or substantial portions of the Software.
|
|
20
|
-
|
|
21
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
-
SOFTWARE.
|
|
28
|
-
|
|
7
|
+
License-Expression: MIT
|
|
29
8
|
Project-URL: homepage, https://github.com/arangodb/python-arango-async
|
|
30
9
|
Keywords: arangodb,python,driver,async
|
|
31
10
|
Classifier: Intended Audience :: Developers
|
|
32
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
33
11
|
Classifier: Natural Language :: English
|
|
34
12
|
Classifier: Operating System :: OS Independent
|
|
35
13
|
Classifier: Programming Language :: Python :: 3
|
|
36
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
37
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
38
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
39
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
40
18
|
Classifier: Topic :: Documentation :: Sphinx
|
|
41
19
|
Classifier: Typing :: Typed
|
|
42
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.10
|
|
43
21
|
Description-Content-Type: text/markdown
|
|
44
22
|
License-File: LICENSE
|
|
45
23
|
Requires-Dist: packaging>=23.1
|
|
@@ -68,7 +46,7 @@ Dynamic: license-file
|
|
|
68
46
|
[](https://github.com/arangodb/python-arango-async/commits/main)
|
|
69
47
|
|
|
70
48
|
[](https://pypi.org/project/python-arango-async/)
|
|
71
|
-
[](https://pypi.org/project/python-arango-async/)
|
|
72
50
|
|
|
73
51
|
[](https://github.com/arangodb/python-arango/blob/main/LICENSE)
|
|
74
52
|
[](https://github.com/psf/black)
|
|
@@ -80,7 +58,7 @@ Dynamic: license-file
|
|
|
80
58
|
Python driver for [ArangoDB](https://www.arangodb.com), a scalable multi-model
|
|
81
59
|
database natively supporting documents, graphs and search.
|
|
82
60
|
|
|
83
|
-
This is the _asyncio_ alternative of the
|
|
61
|
+
This is the _asyncio_ alternative of the [python-arango](https://github.com/arangodb/python-arango)
|
|
84
62
|
driver.
|
|
85
63
|
|
|
86
64
|
**Note: This project is still in active development, features might be added or removed.**
|
|
@@ -88,7 +66,7 @@ driver.
|
|
|
88
66
|
## Requirements
|
|
89
67
|
|
|
90
68
|
- ArangoDB version 3.11+
|
|
91
|
-
- Python version 3.
|
|
69
|
+
- Python version 3.10+
|
|
92
70
|
|
|
93
71
|
## Installation
|
|
94
72
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://github.com/arangodb/python-arango-async/commits/main)
|
|
6
6
|
|
|
7
7
|
[](https://pypi.org/project/python-arango-async/)
|
|
8
|
-
[](https://pypi.org/project/python-arango-async/)
|
|
9
9
|
|
|
10
10
|
[](https://github.com/arangodb/python-arango/blob/main/LICENSE)
|
|
11
11
|
[](https://github.com/psf/black)
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
Python driver for [ArangoDB](https://www.arangodb.com), a scalable multi-model
|
|
18
18
|
database natively supporting documents, graphs and search.
|
|
19
19
|
|
|
20
|
-
This is the _asyncio_ alternative of the
|
|
20
|
+
This is the _asyncio_ alternative of the [python-arango](https://github.com/arangodb/python-arango)
|
|
21
21
|
driver.
|
|
22
22
|
|
|
23
23
|
**Note: This project is still in active development, features might be added or removed.**
|
|
@@ -25,7 +25,7 @@ driver.
|
|
|
25
25
|
## Requirements
|
|
26
26
|
|
|
27
27
|
- ArangoDB version 3.11+
|
|
28
|
-
- Python version 3.
|
|
28
|
+
- Python version 3.10+
|
|
29
29
|
|
|
30
30
|
## Installation
|
|
31
31
|
|
|
@@ -238,6 +238,11 @@ class AQL:
|
|
|
238
238
|
"""Return the name of the current database."""
|
|
239
239
|
return self._executor.db_name
|
|
240
240
|
|
|
241
|
+
@property
|
|
242
|
+
def context(self) -> str:
|
|
243
|
+
"""Return the current API execution context."""
|
|
244
|
+
return self._executor.context
|
|
245
|
+
|
|
241
246
|
@property
|
|
242
247
|
def serializer(self) -> Serializer[Json]:
|
|
243
248
|
"""Return the serializer."""
|
|
@@ -139,7 +139,9 @@ class ArangoClient:
|
|
|
139
139
|
|
|
140
140
|
async def close(self) -> None:
|
|
141
141
|
"""Close HTTP sessions."""
|
|
142
|
-
await asyncio.gather(
|
|
142
|
+
await asyncio.gather(
|
|
143
|
+
*(self._http_client.close_session(session) for session in self._sessions)
|
|
144
|
+
)
|
|
143
145
|
|
|
144
146
|
async def db(
|
|
145
147
|
self,
|
|
@@ -251,6 +251,15 @@ class Collection(Generic[T, U, V]):
|
|
|
251
251
|
"""
|
|
252
252
|
return self._name
|
|
253
253
|
|
|
254
|
+
@property
|
|
255
|
+
def context(self) -> str:
|
|
256
|
+
"""Return the context of the collection.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
str: Context.
|
|
260
|
+
"""
|
|
261
|
+
return self._executor.context
|
|
262
|
+
|
|
254
263
|
@property
|
|
255
264
|
def db_name(self) -> str:
|
|
256
265
|
"""Return the name of the current database.
|
|
@@ -270,9 +279,17 @@ class Collection(Generic[T, U, V]):
|
|
|
270
279
|
"""Return the deserializer."""
|
|
271
280
|
return self._executor.deserializer
|
|
272
281
|
|
|
273
|
-
async def indexes(
|
|
282
|
+
async def indexes(
|
|
283
|
+
self,
|
|
284
|
+
with_stats: Optional[bool] = None,
|
|
285
|
+
with_hidden: Optional[bool] = None,
|
|
286
|
+
) -> Result[List[IndexProperties]]:
|
|
274
287
|
"""Fetch all index descriptions for the given collection.
|
|
275
288
|
|
|
289
|
+
Args:
|
|
290
|
+
with_stats (bool | None): Whether to include figures and estimates in the result.
|
|
291
|
+
with_hidden (bool | None): Whether to include hidden indexes in the result.
|
|
292
|
+
|
|
276
293
|
Returns:
|
|
277
294
|
list: List of index properties.
|
|
278
295
|
|
|
@@ -282,10 +299,16 @@ class Collection(Generic[T, U, V]):
|
|
|
282
299
|
References:
|
|
283
300
|
- `list-all-indexes-of-a-collection <https://docs.arangodb.com/stable/develop/http-api/indexes/#list-all-indexes-of-a-collection>`__
|
|
284
301
|
""" # noqa: E501
|
|
302
|
+
params: Params = dict(collection=self._name)
|
|
303
|
+
if with_stats is not None:
|
|
304
|
+
params["withStats"] = with_stats
|
|
305
|
+
if with_hidden is not None:
|
|
306
|
+
params["withHidden"] = with_hidden
|
|
307
|
+
|
|
285
308
|
request = Request(
|
|
286
309
|
method=Method.GET,
|
|
287
310
|
endpoint="/_api/index",
|
|
288
|
-
params=
|
|
311
|
+
params=params,
|
|
289
312
|
)
|
|
290
313
|
|
|
291
314
|
def response_handler(resp: Response) -> List[IndexProperties]:
|
|
@@ -564,6 +587,7 @@ class StandardCollection(Collection[T, U, V]):
|
|
|
564
587
|
Raises:
|
|
565
588
|
DocumentRevisionError: If the revision is incorrect.
|
|
566
589
|
DocumentGetError: If retrieval fails.
|
|
590
|
+
DocumentParseError: If the document is malformed.
|
|
567
591
|
|
|
568
592
|
References:
|
|
569
593
|
- `get-a-document <https://docs.arangodb.com/stable/develop/http-api/documents/#get-a-document>`__
|
|
@@ -707,6 +731,7 @@ class StandardCollection(Collection[T, U, V]):
|
|
|
707
731
|
|
|
708
732
|
Raises:
|
|
709
733
|
DocumentInsertError: If insertion fails.
|
|
734
|
+
DocumentParseError: If the document is malformed.
|
|
710
735
|
|
|
711
736
|
References:
|
|
712
737
|
- `create-a-document <https://docs.arangodb.com/stable/develop/http-api/documents/#create-a-document>`__
|
|
@@ -177,6 +177,9 @@ class BaseConnection(ABC):
|
|
|
177
177
|
host_index = self._host_resolver.get_host_index()
|
|
178
178
|
for tries in range(self._host_resolver.max_tries):
|
|
179
179
|
try:
|
|
180
|
+
logger.debug(
|
|
181
|
+
f"Sending request to host {host_index} ({tries}): {request}"
|
|
182
|
+
)
|
|
180
183
|
resp = await self._http_client.send_request(
|
|
181
184
|
self._sessions[host_index], request
|
|
182
185
|
)
|
|
@@ -596,7 +596,6 @@ class Database:
|
|
|
596
596
|
)
|
|
597
597
|
|
|
598
598
|
def response_handler(resp: Response) -> StandardCollection[T, U, V]:
|
|
599
|
-
nonlocal doc_serializer, doc_deserializer
|
|
600
599
|
if not resp.is_success:
|
|
601
600
|
raise CollectionCreateError(resp, request)
|
|
602
601
|
if doc_serializer is None:
|
|
@@ -648,7 +647,6 @@ class Database:
|
|
|
648
647
|
)
|
|
649
648
|
|
|
650
649
|
def response_handler(resp: Response) -> bool:
|
|
651
|
-
nonlocal ignore_missing
|
|
652
650
|
if resp.is_success:
|
|
653
651
|
return True
|
|
654
652
|
if resp.status_code == HTTP_NOT_FOUND and ignore_missing:
|
|
@@ -1001,7 +999,6 @@ class Database:
|
|
|
1001
999
|
)
|
|
1002
1000
|
|
|
1003
1001
|
def response_handler(resp: Response) -> bool:
|
|
1004
|
-
nonlocal ignore_failure
|
|
1005
1002
|
if resp.is_success:
|
|
1006
1003
|
return True
|
|
1007
1004
|
if ignore_failure:
|
|
@@ -1046,7 +1043,6 @@ class Database:
|
|
|
1046
1043
|
)
|
|
1047
1044
|
|
|
1048
1045
|
def response_handler(resp: Response) -> bool:
|
|
1049
|
-
nonlocal ignore_failure
|
|
1050
1046
|
if resp.is_success:
|
|
1051
1047
|
return True
|
|
1052
1048
|
if ignore_failure:
|
|
@@ -33,6 +33,8 @@ class HTTPClient(ABC): # pragma: no cover
|
|
|
33
33
|
class MyCustomHTTPClient(HTTPClient):
|
|
34
34
|
def create_session(self, host):
|
|
35
35
|
pass
|
|
36
|
+
async def close_session(self, session):
|
|
37
|
+
pass
|
|
36
38
|
async def send_request(self, session, request):
|
|
37
39
|
pass
|
|
38
40
|
"""
|
|
@@ -52,6 +54,18 @@ class HTTPClient(ABC): # pragma: no cover
|
|
|
52
54
|
"""
|
|
53
55
|
raise NotImplementedError
|
|
54
56
|
|
|
57
|
+
@abstractmethod
|
|
58
|
+
async def close_session(self, session: Any) -> None:
|
|
59
|
+
"""Close the session.
|
|
60
|
+
|
|
61
|
+
Note:
|
|
62
|
+
This method must be overridden by the user.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
session (Any): Client session object.
|
|
66
|
+
"""
|
|
67
|
+
raise NotImplementedError
|
|
68
|
+
|
|
55
69
|
@abstractmethod
|
|
56
70
|
async def send_request(
|
|
57
71
|
self,
|
|
@@ -129,6 +143,14 @@ class AioHTTPClient(HTTPClient):
|
|
|
129
143
|
read_bufsize=self._read_bufsize,
|
|
130
144
|
)
|
|
131
145
|
|
|
146
|
+
async def close_session(self, session: ClientSession) -> None:
|
|
147
|
+
"""Close the session.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
session (Any): Client session object.
|
|
151
|
+
"""
|
|
152
|
+
await session.close()
|
|
153
|
+
|
|
132
154
|
async def send_request(
|
|
133
155
|
self,
|
|
134
156
|
session: ClientSession,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.3"
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
AQL
|
|
2
|
+
----
|
|
3
|
+
|
|
4
|
+
**ArangoDB Query Language (AQL)** is used to read and write data. It is similar
|
|
5
|
+
to SQL for relational databases, but without the support for data definition
|
|
6
|
+
operations such as creating or deleting :doc:`databases <database>`,
|
|
7
|
+
:doc:`collections <collection>` or :doc:`indexes <indexes>`. For more
|
|
8
|
+
information, refer to `ArangoDB Manual`_.
|
|
9
|
+
|
|
10
|
+
.. _ArangoDB Manual: https://docs.arangodb.com
|
|
11
|
+
|
|
12
|
+
AQL Queries
|
|
13
|
+
===========
|
|
14
|
+
|
|
15
|
+
AQL queries are invoked from AQL wrapper. Executing queries returns
|
|
16
|
+
:doc:`cursors <cursor>`.
|
|
17
|
+
|
|
18
|
+
**Example:**
|
|
19
|
+
|
|
20
|
+
.. code-block:: python
|
|
21
|
+
|
|
22
|
+
from arangoasync import ArangoClient, AQLQueryKillError
|
|
23
|
+
from arangoasync.auth import Auth
|
|
24
|
+
|
|
25
|
+
# Initialize the client for ArangoDB.
|
|
26
|
+
async with ArangoClient(hosts="http://localhost:8529") as client:
|
|
27
|
+
auth = Auth(username="root", password="passwd")
|
|
28
|
+
|
|
29
|
+
# Connect to "test" database as root user.
|
|
30
|
+
db = await client.db("test", auth=auth)
|
|
31
|
+
|
|
32
|
+
# Get the API wrapper for "students" collection.
|
|
33
|
+
students = db.collection("students")
|
|
34
|
+
|
|
35
|
+
# Insert some test documents into "students" collection.
|
|
36
|
+
await students.insert_many([
|
|
37
|
+
{"_key": "Abby", "age": 22},
|
|
38
|
+
{"_key": "John", "age": 18},
|
|
39
|
+
{"_key": "Mary", "age": 21}
|
|
40
|
+
])
|
|
41
|
+
|
|
42
|
+
# Get the AQL API wrapper.
|
|
43
|
+
aql = db.aql
|
|
44
|
+
|
|
45
|
+
# Retrieve the execution plan without running the query.
|
|
46
|
+
plan = await aql.explain("FOR doc IN students RETURN doc")
|
|
47
|
+
|
|
48
|
+
# Validate the query without executing it.
|
|
49
|
+
validate = await aql.validate("FOR doc IN students RETURN doc")
|
|
50
|
+
|
|
51
|
+
# Execute the query
|
|
52
|
+
cursor = await db.aql.execute(
|
|
53
|
+
"FOR doc IN students FILTER doc.age < @value RETURN doc",
|
|
54
|
+
bind_vars={"value": 19}
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Iterate through the result cursor
|
|
58
|
+
student_keys = []
|
|
59
|
+
async for doc in cursor:
|
|
60
|
+
student_keys.append(doc)
|
|
61
|
+
|
|
62
|
+
# List currently running queries.
|
|
63
|
+
queries = await aql.queries()
|
|
64
|
+
|
|
65
|
+
# List any slow queries.
|
|
66
|
+
slow_queries = await aql.slow_queries()
|
|
67
|
+
|
|
68
|
+
# Clear slow AQL queries if any.
|
|
69
|
+
await aql.clear_slow_queries()
|
|
70
|
+
|
|
71
|
+
# Retrieve AQL query tracking properties.
|
|
72
|
+
await aql.tracking()
|
|
73
|
+
|
|
74
|
+
# Configure AQL query tracking properties.
|
|
75
|
+
await aql.set_tracking(
|
|
76
|
+
max_slow_queries=10,
|
|
77
|
+
track_bind_vars=True,
|
|
78
|
+
track_slow_queries=True
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Kill a running query (this should fail due to invalid ID).
|
|
82
|
+
try:
|
|
83
|
+
await aql.kill("some_query_id")
|
|
84
|
+
except AQLQueryKillError as err:
|
|
85
|
+
assert err.http_code == 404
|
|
86
|
+
|
|
87
|
+
See :class:`arangoasync.aql.AQL` for API specification.
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
AQL User Functions
|
|
91
|
+
==================
|
|
92
|
+
|
|
93
|
+
**AQL User Functions** are custom functions you define in Javascript to extend
|
|
94
|
+
AQL functionality. They are somewhat similar to SQL procedures.
|
|
95
|
+
|
|
96
|
+
**Example:**
|
|
97
|
+
|
|
98
|
+
.. code-block:: python
|
|
99
|
+
|
|
100
|
+
from arangoasync import ArangoClient
|
|
101
|
+
from arangoasync.auth import Auth
|
|
102
|
+
|
|
103
|
+
# Initialize the client for ArangoDB.
|
|
104
|
+
async with ArangoClient(hosts="http://localhost:8529") as client:
|
|
105
|
+
auth = Auth(username="root", password="passwd")
|
|
106
|
+
|
|
107
|
+
# Connect to "test" database as root user.
|
|
108
|
+
db = await client.db("test", auth=auth)
|
|
109
|
+
|
|
110
|
+
# Get the AQL API wrapper.
|
|
111
|
+
aql = db.aql
|
|
112
|
+
|
|
113
|
+
# Create a new AQL user function.
|
|
114
|
+
await aql.create_function(
|
|
115
|
+
# Grouping by name prefix is supported.
|
|
116
|
+
name="functions::temperature::converter",
|
|
117
|
+
code="function (celsius) { return celsius * 1.8 + 32; }"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# List AQL user functions.
|
|
121
|
+
functions = await aql.functions()
|
|
122
|
+
|
|
123
|
+
# Delete an existing AQL user function.
|
|
124
|
+
await aql.delete_function("functions::temperature::converter")
|
|
125
|
+
|
|
126
|
+
See :class:`arangoasync.aql.AQL` for API specification.
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
AQL Query Cache
|
|
130
|
+
===============
|
|
131
|
+
|
|
132
|
+
**AQL Query Cache** is used to minimize redundant calculation of the same query
|
|
133
|
+
results. It is useful when read queries are issued frequently and write queries
|
|
134
|
+
are not.
|
|
135
|
+
|
|
136
|
+
**Example:**
|
|
137
|
+
|
|
138
|
+
.. code-block:: python
|
|
139
|
+
|
|
140
|
+
from arangoasync import ArangoClient
|
|
141
|
+
from arangoasync.auth import Auth
|
|
142
|
+
|
|
143
|
+
# Initialize the client for ArangoDB.
|
|
144
|
+
async with ArangoClient(hosts="http://localhost:8529") as client:
|
|
145
|
+
auth = Auth(username="root", password="passwd")
|
|
146
|
+
|
|
147
|
+
# Connect to "test" database as root user.
|
|
148
|
+
db = await client.db("test", auth=auth)
|
|
149
|
+
|
|
150
|
+
# Get the AQL API wrapper.
|
|
151
|
+
aql = db.aql
|
|
152
|
+
|
|
153
|
+
# Retrieve AQL query cache properties.
|
|
154
|
+
await aql.cache.properties()
|
|
155
|
+
|
|
156
|
+
# Configure AQL query cache properties.
|
|
157
|
+
await aql.cache.configure(mode="demand", max_results=10000)
|
|
158
|
+
|
|
159
|
+
# List results cache entries.
|
|
160
|
+
entries = await aql.cache.entries()
|
|
161
|
+
|
|
162
|
+
# List plan cache entries.
|
|
163
|
+
plan_entries = await aql.cache.plan_entries()
|
|
164
|
+
|
|
165
|
+
# Clear results in AQL query cache.
|
|
166
|
+
await aql.cache.clear()
|
|
167
|
+
|
|
168
|
+
# Clear results in AQL query plan cache.
|
|
169
|
+
await aql.cache.clear_plan()
|
|
170
|
+
|
|
171
|
+
See :class:`arangoasync.aql.AQLQueryCache` for API specification.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Async API Execution
|
|
2
|
+
-------------------
|
|
3
|
+
|
|
4
|
+
In **asynchronous API executions**, the driver sends API requests to ArangoDB in
|
|
5
|
+
fire-and-forget style. The server processes them in the background, and
|
|
6
|
+
the results can be retrieved once available via :class:`arangoasync.job.AsyncJob` objects.
|
|
7
|
+
|
|
8
|
+
**Example:**
|
|
9
|
+
|
|
10
|
+
.. code-block:: python
|
|
11
|
+
|
|
12
|
+
import time
|
|
13
|
+
from arangoasync import ArangoClient
|
|
14
|
+
from arangoasync.auth import Auth
|
|
15
|
+
from arangoasync.errno import HTTP_BAD_PARAMETER
|
|
16
|
+
from arangoasync.exceptions import (
|
|
17
|
+
AQLQueryExecuteError,
|
|
18
|
+
AsyncJobCancelError,
|
|
19
|
+
AsyncJobClearError,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# Initialize the client for ArangoDB.
|
|
23
|
+
async with ArangoClient(hosts="http://localhost:8529") as client:
|
|
24
|
+
auth = Auth(username="root", password="passwd")
|
|
25
|
+
|
|
26
|
+
# Connect to "test" database as root user.
|
|
27
|
+
db = await client.db("test", auth=auth)
|
|
28
|
+
|
|
29
|
+
# Begin async execution. This returns an instance of AsyncDatabase, a
|
|
30
|
+
# database-level API wrapper tailored specifically for async execution.
|
|
31
|
+
async_db = db.begin_async_execution(return_result=True)
|
|
32
|
+
|
|
33
|
+
# Child wrappers are also tailored for async execution.
|
|
34
|
+
async_aql = async_db.aql
|
|
35
|
+
async_col = async_db.collection("students")
|
|
36
|
+
|
|
37
|
+
# API execution context is always set to "async".
|
|
38
|
+
assert async_db.context == "async"
|
|
39
|
+
assert async_aql.context == "async"
|
|
40
|
+
assert async_col.context == "async"
|
|
41
|
+
|
|
42
|
+
# On API execution, AsyncJob objects are returned instead of results.
|
|
43
|
+
job1 = await async_col.insert({"_key": "Neal"})
|
|
44
|
+
job2 = await async_col.insert({"_key": "Lily"})
|
|
45
|
+
job3 = await async_aql.execute("RETURN 100000")
|
|
46
|
+
job4 = await async_aql.execute("INVALID QUERY") # Fails due to syntax error.
|
|
47
|
+
|
|
48
|
+
# Retrieve the status of each async job.
|
|
49
|
+
for job in [job1, job2, job3, job4]:
|
|
50
|
+
# Job status can be "pending" or "done".
|
|
51
|
+
assert await job.status() in {"pending", "done"}
|
|
52
|
+
|
|
53
|
+
# Let's wait until the jobs are finished.
|
|
54
|
+
while await job.status() != "done":
|
|
55
|
+
time.sleep(0.1)
|
|
56
|
+
|
|
57
|
+
# Retrieve the results of successful jobs.
|
|
58
|
+
metadata = await job1.result()
|
|
59
|
+
assert metadata["_id"] == "students/Neal"
|
|
60
|
+
|
|
61
|
+
metadata = await job2.result()
|
|
62
|
+
assert metadata["_id"] == "students/Lily"
|
|
63
|
+
|
|
64
|
+
cursor = await job3.result()
|
|
65
|
+
assert await cursor.next() == 100000
|
|
66
|
+
|
|
67
|
+
# If a job fails, the exception is propagated up during result retrieval.
|
|
68
|
+
try:
|
|
69
|
+
result = await job4.result()
|
|
70
|
+
except AQLQueryExecuteError as err:
|
|
71
|
+
assert err.http_code == HTTP_BAD_PARAMETER
|
|
72
|
+
|
|
73
|
+
# Cancel a job. Only pending jobs still in queue may be cancelled.
|
|
74
|
+
# Since job3 is done, there is nothing to cancel and an exception is raised.
|
|
75
|
+
try:
|
|
76
|
+
await job3.cancel()
|
|
77
|
+
except AsyncJobCancelError as err:
|
|
78
|
+
print(err.message)
|
|
79
|
+
|
|
80
|
+
# Clear the result of a job from ArangoDB server to free up resources.
|
|
81
|
+
# Result of job4 was removed from the server automatically upon retrieval,
|
|
82
|
+
# so attempt to clear it raises an exception.
|
|
83
|
+
try:
|
|
84
|
+
await job4.clear()
|
|
85
|
+
except AsyncJobClearError as err:
|
|
86
|
+
print(err.message)
|
|
87
|
+
|
|
88
|
+
# List the IDs of the first 100 async jobs completed.
|
|
89
|
+
jobs_done = await db.async_jobs(status="done", count=100)
|
|
90
|
+
|
|
91
|
+
# List the IDs of the first 100 async jobs still pending.
|
|
92
|
+
jobs_pending = await db.async_jobs(status='pending', count=100)
|
|
93
|
+
|
|
94
|
+
# Clear all async jobs still sitting on the server.
|
|
95
|
+
await db.clear_async_jobs()
|
|
96
|
+
|
|
97
|
+
Cursors returned from async API wrappers will no longer send async requests when they fetch more results, but behave
|
|
98
|
+
like regular cursors instead. This makes sense, because the point of cursors is iteration, whereas async jobs are meant
|
|
99
|
+
for one-shot requests. However, the first result retrieval is still async, and only then the cursor is returned, making
|
|
100
|
+
async AQL requests effective for queries with a long execution time.
|
|
101
|
+
|
|
102
|
+
**Example:**
|
|
103
|
+
|
|
104
|
+
.. code-block:: python
|
|
105
|
+
|
|
106
|
+
from arangoasync import ArangoClient
|
|
107
|
+
from arangoasync.auth import Auth
|
|
108
|
+
|
|
109
|
+
# Initialize the client for ArangoDB.
|
|
110
|
+
async with ArangoClient(hosts="http://localhost:8529") as client:
|
|
111
|
+
auth = Auth(username="root", password="passwd")
|
|
112
|
+
|
|
113
|
+
# Connect to "test" database as root user.
|
|
114
|
+
db = await client.db("test", auth=auth)
|
|
115
|
+
|
|
116
|
+
# Get the API wrapper for "students" collection.
|
|
117
|
+
students = db.collection("students")
|
|
118
|
+
|
|
119
|
+
# Insert some documents into the collection.
|
|
120
|
+
await students.insert_many([{"_key": "Neal"}, {"_key": "Lily"}])
|
|
121
|
+
|
|
122
|
+
# Begin async execution.
|
|
123
|
+
async_db = db.begin_async_execution(return_result=True)
|
|
124
|
+
|
|
125
|
+
aql = async_db.aql
|
|
126
|
+
job = await aql.execute(
|
|
127
|
+
f"FOR d IN {students.name} SORT d._key RETURN d",
|
|
128
|
+
count=True,
|
|
129
|
+
batch_size=1,
|
|
130
|
+
ttl=1000,
|
|
131
|
+
)
|
|
132
|
+
await job.wait()
|
|
133
|
+
|
|
134
|
+
# Iterate through the cursor.
|
|
135
|
+
# Although the request to fetch the cursor is async, its underlying executor is no longer async.
|
|
136
|
+
# Next batches will be fetched in real-time.
|
|
137
|
+
doc_cnt = 0
|
|
138
|
+
cursor = await job.result()
|
|
139
|
+
async with cursor as ctx:
|
|
140
|
+
async for _ in ctx:
|
|
141
|
+
doc_cnt += 1
|
|
142
|
+
assert doc_cnt == 2
|
|
143
|
+
|
|
144
|
+
.. note::
|
|
145
|
+
Be mindful of server-side memory capacity when issuing a large number of
|
|
146
|
+
async requests in small time interval.
|
|
147
|
+
|
|
148
|
+
See :class:`arangoasync.database.AsyncDatabase` and :class:`arangoasync.job.AsyncJob` for API specification.
|