Skip to content

Commit 3d1cad5

Browse files
committed
Adding documentation
1 parent 61ba99b commit 3d1cad5

17 files changed

+528
-8
lines changed

README.md

+67-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
![Logo](docs/static/logo.png)
2+
3+
[![CircleCI](https://dl.circleci.com/status-badge/img/gh/arangodb/python-arango-async/tree/main.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/arangodb/python-arango-async/tree/main)
4+
[![CodeQL](https://github.com/arangodb/python-arango-async/actions/workflows/codeql.yaml/badge.svg)](https://github.com/arangodb/python-arango-async/actions/workflows/codeql.yaml)
5+
[![Last commit](https://img.shields.io/github/last-commit/arangodb/python-arango-async)](https://github.com/arangodb/python-arango-async/commits/main)
6+
7+
[![PyPI version badge](https://img.shields.io/pypi/v/python-arango-async?color=3775A9&style=for-the-badge&logo=pypi&logoColor=FFD43B)](https://pypi.org/project/python-arango-async/)
8+
[![Python versions badge](https://img.shields.io/badge/3.9%2B-3776AB?style=for-the-badge&logo=python&logoColor=FFD43B&label=Python)](https://pypi.org/project/python-arango-async/)
9+
10+
[![License](https://img.shields.io/github/license/arangodb/python-arango?color=9E2165&style=for-the-badge)](https://github.com/arangodb/python-arango/blob/main/LICENSE)
11+
[![Code style: black](https://img.shields.io/static/v1?style=for-the-badge&label=code%20style&message=black&color=black)](https://github.com/psf/black)
12+
[![Downloads](https://img.shields.io/pepy/dt/python-arango-async?style=for-the-badge&color=282661
13+
)](https://pepy.tech/project/python-arango-async)
14+
115
# python-arango-async
216

317
Python driver for [ArangoDB](https://www.arangodb.com), a scalable multi-model
@@ -6,9 +20,60 @@ database natively supporting documents, graphs and search.
620
This is the _asyncio_ alternative of the officially supported [python-arango](https://github.com/arangodb/python-arango)
721
driver.
822

9-
**Note**: This driver is still in development and not yet ready for production use.
23+
**Note: This project is still in active development, features might be added or removed.**
1024

1125
## Requirements
1226

13-
- ArangoDB version 3.10+
27+
- ArangoDB version 3.11+
1428
- Python version 3.9+
29+
30+
## Installation
31+
32+
```shell
33+
pip install python-arango-async --upgrade
34+
```
35+
36+
## Getting Started
37+
38+
Here is a simple usage example:
39+
40+
```python
41+
from arangoasync import ArangoClient
42+
from arangoasync.auth import Auth
43+
44+
45+
async def main():
46+
# Initialize the client for ArangoDB.
47+
async with ArangoClient(hosts="http://localhost:8529") as client:
48+
auth = Auth(username="root", password="passwd")
49+
50+
# Connect to "_system" database as root user.
51+
sys_db = await client.db("_system", auth=auth)
52+
53+
# Create a new database named "test".
54+
await sys_db.create_database("test")
55+
56+
# Connect to "test" database as root user.
57+
db = await client.db("test", auth=auth)
58+
59+
# Create a new collection named "students".
60+
students = await db.create_collection("students")
61+
62+
# Add a persistent index to the collection.
63+
await students.add_index(type="persistent", fields=["name"], options={"unique": True})
64+
65+
# Insert new documents into the collection.
66+
await students.insert({"name": "jane", "age": 39})
67+
await students.insert({"name": "josh", "age": 18})
68+
await students.insert({"name": "judy", "age": 21})
69+
70+
# Execute an AQL query and iterate through the result cursor.
71+
cursor = await db.aql.execute("FOR doc IN students RETURN doc")
72+
async with cursor:
73+
student_names = []
74+
async for doc in cursor:
75+
student_names.append(doc["name"])
76+
77+
```
78+
79+
Please see the [documentation](https://python-arango-async.readthedocs.io/en/latest/) for more details.

arangoasync/__init__.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import logging
1+
import arangoasync.errno as errno # noqa: F401
2+
from arangoasync.client import ArangoClient # noqa: F401
3+
from arangoasync.exceptions import * # noqa: F401 F403
24

35
from .version import __version__
4-
5-
logger = logging.getLogger(__name__)

arangoasync/connection.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111

1212
from jwt import ExpiredSignatureError
1313

14-
from arangoasync import errno, logger
1514
from arangoasync.auth import Auth, JwtToken
1615
from arangoasync.compression import CompressionManager
16+
from arangoasync.errno import HTTP_UNAUTHORIZED
1717
from arangoasync.exceptions import (
1818
AuthHeaderError,
1919
ClientConnectionAbortedError,
@@ -24,6 +24,7 @@
2424
ServerConnectionError,
2525
)
2626
from arangoasync.http import HTTPClient
27+
from arangoasync.logger import logger
2728
from arangoasync.request import Method, Request
2829
from arangoasync.resolver import HostResolver
2930
from arangoasync.response import Response
@@ -417,7 +418,7 @@ async def send_request(self, request: Request) -> Response:
417418

418419
resp = await self.process_request(request)
419420
if (
420-
resp.status_code == errno.HTTP_UNAUTHORIZED
421+
resp.status_code == HTTP_UNAUTHORIZED
421422
and self._token is not None
422423
and self._token.needs_refresh(self._expire_leeway)
423424
):

arangoasync/logger.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import logging
2+
3+
logger = logging.getLogger("arangoasync")

docs/aql.rst

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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

docs/async.rst

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Async API Execution
2+
-------------------
3+
4+
In **asynchronous API executions**, python-arango-async sends API requests to ArangoDB in
5+
fire-and-forget style. The server processes the requests in the background, and
6+
the results can be retrieved once available via `AsyncJob` objects.

docs/collection.rst

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Collections
2+
-----------
3+
4+
A **collection** contains :doc:`documents <document>`. It is uniquely identified
5+
by its name which must consist only of hyphen, underscore and alphanumeric
6+
characters.
7+
8+
Here is an example showing how you can manage standard collections:
9+
10+
.. code-block:: python
11+
12+
from arangoasync import ArangoClient
13+
from arangoasync.auth import Auth
14+
15+
# Initialize the client for ArangoDB.
16+
async with ArangoClient(hosts="http://localhost:8529") as client:
17+
auth = Auth(username="root", password="passwd")
18+
19+
# Connect to "test" database as root user.
20+
db = await client.db("test", auth=auth)
21+
22+
# List all collections in the database.
23+
await db.collections()
24+
25+
# Create a new collection named "students" if it does not exist.
26+
# This returns an API wrapper for "students" collection.
27+
if await db.has_collection("students"):
28+
students = db.collection("students")
29+
else:
30+
students = await db.create_collection("students")
31+
32+
# Retrieve collection properties.
33+
name = students.name
34+
db_name = students.db_name
35+
properties = await students.properties()
36+
count = await students.count()
37+
38+
# Perform various operations.
39+
await students.truncate()
40+
41+
# Delete the collection.
42+
await db.delete_collection("students")

docs/database.rst

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
Databases
2+
---------
3+
4+
ArangoDB server can have an arbitrary number of **databases**. Each database
5+
has its own set of :doc:`collections <collection>` and graphs.
6+
There is a special database named ``_system``, which cannot be dropped and
7+
provides operations for managing users, permissions and other databases. Most
8+
of the operations can only be executed by admin users. See :doc:`user` for more
9+
information.
10+
11+
**Example:**
12+
13+
.. code-block:: python
14+
15+
from arangoasync import ArangoClient
16+
from arangoasync.auth import Auth
17+
18+
# Initialize the client for ArangoDB.
19+
async with ArangoClient(hosts="http://localhost:8529") as client:
20+
auth = Auth(username="root", password="passwd")
21+
22+
# Connect to "_system" database as root user.
23+
sys_db = await client.db("_system", auth=auth)
24+
25+
# List all databases.
26+
await sys_db.databases()
27+
28+
# Create a new database named "test" if it does not exist.
29+
# Only root user has access to it at time of its creation.
30+
if not await sys_db.has_database("test"):
31+
await sys_db.create_database("test")
32+
33+
# Delete the database.
34+
await sys_db.delete_database("test")
35+
36+
# Create a new database named "test" along with a new set of users.
37+
# Only "jane", "john", "jake" and root user have access to it.
38+
if not await sys_db.has_database("test"):
39+
await sys_db.create_database(
40+
name="test",
41+
users=[
42+
{"username": "jane", "password": "foo", "active": True},
43+
{"username": "john", "password": "bar", "active": True},
44+
{"username": "jake", "password": "baz", "active": True},
45+
],
46+
)
47+
48+
# Connect to the new "test" database as user "jane".
49+
db = await client.db("test", auth=Auth("jane", "foo"))
50+
51+
# Make sure that user "jane" has read and write permissions.
52+
await sys_db.update_permission(username="jane", permission="rw", database="test")
53+
54+
# Retrieve various database and server information.
55+
name = db.name
56+
version = await db.version()
57+
status = await db.status()
58+
collections = await db.collections()
59+
60+
# Delete the database. Note that the new users will remain.
61+
await sys_db.delete_database("test")

docs/document.rst

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
Documents
2+
---------
3+
4+
In python-arango-async, a **document** is an object with the following
5+
properties:
6+
7+
* Is JSON serializable.
8+
* May be nested to an arbitrary depth.
9+
* May contain lists.
10+
* Contains the ``_key`` field, which identifies the document uniquely within a
11+
specific collection.
12+
* Contains the ``_id`` field (also called the *handle*), which identifies the
13+
document uniquely across all collections within a database. This ID is a
14+
combination of the collection name and the document key using the format
15+
``{collection}/{key}`` (see example below).
16+
* Contains the ``_rev`` field. ArangoDB supports MVCC (Multiple Version
17+
Concurrency Control) and is capable of storing each document in multiple
18+
revisions. Latest revision of a document is indicated by this field. The
19+
field is populated by ArangoDB and is not required as input unless you want
20+
to validate a document against its current revision.
21+
22+
For more information on documents and associated terminologies, refer to
23+
`ArangoDB manual`_. Here is an example of a valid document in "students"
24+
collection:
25+
26+
.. _ArangoDB manual: https://docs.arangodb.com
27+
28+
.. testcode::
29+
30+
{
31+
'_id': 'students/bruce',
32+
'_key': 'bruce',
33+
'_rev': '_Wm3dzEi--_',
34+
'first_name': 'Bruce',
35+
'last_name': 'Wayne',
36+
'address': {
37+
'street' : '1007 Mountain Dr.',
38+
'city': 'Gotham',
39+
'state': 'NJ'
40+
},
41+
'is_rich': True,
42+
'friends': ['robin', 'gordon']
43+
}
44+
45+
Standard documents are managed via collection API wrapper:
46+
47+
.. code-block:: python
48+
49+
from arangoasync import ArangoClient
50+
from arangoasync.auth import Auth
51+
52+
# Initialize the client for ArangoDB.
53+
async with ArangoClient(hosts="http://localhost:8529") as client:
54+
auth = Auth(username="root", password="passwd")
55+
56+
# Connect to "test" database as root user.
57+
db = await client.db("test", auth=auth)
58+
59+
# Get the API wrapper for "students" collection.
60+
students = db.collection("students")
61+
62+
# Create some test documents to play around with.
63+
lola = {"_key": "lola", "GPA": 3.5, "first": "Lola", "last": "Martin"}
64+
abby = {"_key": "abby", "GPA": 3.2, "first": "Abby", "last": "Page"}
65+
john = {"_key": "john", "GPA": 3.6, "first": "John", "last": "Kim"}
66+
emma = {"_key": "emma", "GPA": 4.0, "first": "Emma", "last": "Park"}
67+
68+
# Insert a new document. This returns the document metadata.
69+
metadata = await students.insert(lola)
70+
assert metadata["_id"] == "students/lola"
71+
assert metadata["_key"] == "lola"
72+
73+
# Insert multiple documents.
74+
await students.insert_many([abby, john, emma])
75+
76+
# Check if documents exist in the collection.
77+
assert await students.has("lola")
78+
79+
# Retrieve the total document count.
80+
count = await students.count()
81+
82+
# Retrieve one or more matching documents.
83+
async for student in await students.find({"first": "John"}):
84+
assert student["_key"] == "john"
85+
assert student["GPA"] == 3.6
86+
assert student["last"] == "Kim"
87+
88+
# Retrieve one or more matching documents, sorted by a field.
89+
async for student in await students.find({"first": "John"}, sort=[{"sort_by": "GPA", "sort_order": "DESC"}]):
90+
assert student["_key"] == "john"
91+
assert student["GPA"] == 3.6
92+
assert student["last"] == "Kim"
93+
94+
# Retrieve a document by key.
95+
await students.get("john")
96+
97+
# Retrieve a document by ID.
98+
await students.get("students/john")
99+
100+
# Retrieve a document by body with "_id" field.
101+
await students.get({"_id": "students/john"})
102+
103+
# Retrieve a document by body with "_key" field.
104+
await students.get({"_key": "john"})
105+
106+
# Retrieve multiple documents by ID, key or body.
107+
await students.get_many(["abby", "students/lola", {"_key": "john"}])
108+
109+
# Update a single document.
110+
lola["GPA"] = 2.6
111+
await students.update(lola)
112+
113+
# Update one or more matching documents.
114+
await students.update_match({"last": "Park"}, {"GPA": 3.0})
115+
116+
# Replace a single document.
117+
emma["GPA"] = 3.1
118+
await students.replace(emma)
119+
120+
# Replace one or more matching documents.
121+
becky = {"first": "Becky", "last": "Solis", "GPA": "3.3"}
122+
await students.replace_match({"first": "Emma"}, becky)
123+
124+
# Delete a document by body with "_id" or "_key" field.
125+
await students.delete(emma)
126+
127+
# Delete multiple documents. Missing ones are ignored.
128+
await students.delete_many([abby, emma])
129+
130+
# Delete one or more matching documents.
131+
await students.delete_match({"first": "Emma"})

docs/errno.rst

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Error Codes
2+
-----------
3+
4+
Python-Arango-Async provides ArangoDB error code constants for convenience.
5+
6+
**Example**
7+
8+
.. testcode::
9+
10+
from arangoasync import errno
11+
12+
# Some examples
13+
assert errno.NOT_IMPLEMENTED == 9
14+
assert errno.DOCUMENT_REV_BAD == 1239
15+
assert errno.DOCUMENT_NOT_FOUND == 1202
16+
17+
For more information, refer to `ArangoDB manual`_.
18+
19+
.. _ArangoDB manual: https://www.arangodb.com/docs/stable/appendix-error-codes.html

0 commit comments

Comments
 (0)