python-arango Documentation

repository·main·Indexed 19 days ago

https://github.com/arangodb/python-arango

A Python driver for ArangoDB, a multi-model database supporting documents, graphs, and search. It provides an idiomatic Python interface to interact with ArangoDB instances, including support for AQL query execution, graph operations, server administration, and analyzer management. Requires ArangoDB version 3.11 or higher and Python version 3.9 or higher.

Tokens
36.6K
Snippets
100
Records
124
Agent score
65%

What's inside python-arango

  1. What is the Write-Ahead Log (WAL)?

    main

    The Write-Ahead Log (WAL) is a set of append-only files that record all write operations on the ArangoDB server. It is primarily used for:

    • Performing data recovery after a system crash.
    • Synchronizing slave databases with master databases in replicated environments.

    Important Security Note: WAL operations can only be performed by admin users and must be accessed via the _system database.

  2. What is a document in python-arango?

    main

    In python-arango, a document is a Python dictionary that is JSON serializable and can be nested to an arbitrary depth.

    Key properties include:

    • _key: A unique identifier for the document within a specific collection.
    • _id (the handle): A unique identifier across all collections in a database, formatted as {collection}/{key}.
    • _rev: The current revision of the document, used for MVCC (Multiple Version Concurrency Control). This is populated by ArangoDB.

    Edge documents (edges) are a special type of document used in edge collections. They are similar to standard documents but must include two additional required fields:

    • _from: The handle of the source vertex.
    • _to: The handle of the target vertex.
    # Example of a standard document
    {
        '_id': 'students/bruce',
        '_key': 'bruce',
        '_rev': '_Wm3dzEi--_',
        'first_name': 'Bruce',
        'last_name': 'Wayne',
        'address': {
            'street' : '1007 Mountain Dr.',
            'city': 'Gotham',
            'state': 'NJ'
        },
        'is_rich': True,
        'friends': ['robin', 'gordon']
    }
    
    # Example of an edge document
    {
        '_id': 'friends/001',
        '_key': '001',
        '_rev': '_Wm3d4le--_',
        '_from': 'students/john',
        '_to': 'students/jane',
        'closeness': 9.5
    }
  3. How asynchronous API execution works in python-arango

    main

    In asynchronous API executions, python-arango sends API requests to ArangoDB in a "fire-and-forget" style. Instead of waiting for the server to respond, the client immediately returns an AsyncJob object. The server processes the request in the background, and you can later retrieve the results or check the status using the AsyncJob instance.

    Key Concepts:

    • Async Wrappers: To use async execution, you must call .begin_async_execution(return_result=True) on a database object. This returns an AsyncDatabase instance. All child wrappers (like async_db.aql or async_db.collection('name')) derived from this instance will also operate in async mode.
    • Execution Context: When using these wrappers, the .context attribute is set to 'async'.
    • AsyncJob Lifecycle: When an API call is made via an async wrapper, it returns an AsyncJob. You can poll job.status() which returns either 'pending' or 'done'. Once the status is 'done', you can call job.result() to get the actual data.
    • Error Handling: If an asynchronous operation fails on the server, the exception (e.g., AQLQueryExecuteError) is not raised when the command is issued, but rather when you attempt to call .result() on the AsyncJob.

    Warning: Be mindful of server-side memory capacity when issuing a large number of async requests in a short time interval.

    from arango import ArangoClient
    
    client = ArangoClient()
    db = client.db('test', username='root', password='passwd')
    
    # Transition to async mode
    async_db = db.begin_async_execution(return_result=True)
    async_col = async_db.collection('students')
    
    # Returns an AsyncJob immediately
    job = async_col.insert({'_key': 'Neal'})
    
    # Wait for completion
    while job.status() != 'done':
        pass
    
    # Retrieve result
    result = job.result()
  4. Configure Edge Definitions in a Graph

    main

    An edge definition specifies a directed relation within a graph. It defines which edge collection links which vertex collections. Each definition requires:

    • From Vertex Collections: The source collections.
    • To Vertex Collections: The target collections.
    • Edge Collection: The collection containing the edges.

    You can manage these via the graph object using create_edge_definition, replace_edge_definition, and delete_edge_definition. Using delete_edge_definition with purge=True will also delete the associated collections.

    from arango import ArangoClient
    
    client = ArangoClient()
    db = client.db('test', username='root', password='passwd')
    
    if db.has_graph('school'):
        school = db.graph('school')
    else:
        school = db.create_graph('school')
    
    # Create an edge definition
    if not school.has_edge_definition('teach'):
        teach = school.create_edge_definition(
            edge_collection='teach',
            from_vertex_collections=['teachers'],
            to_vertex_collections=['lectures']
        )
    
    # List edge definitions
    print(school.edge_definitions())
    
    # Replace an existing edge definition
    school.replace_edge_definition(
        edge_collection='teach',
        from_vertex_collections=['teachers'],
        to_vertex_collections=['lectures']
    )
    
    # Delete the edge definition (and its collections if purge=True)
    school.delete_edge_definition('teach', purge=True)
  5. How Overload Control works in python-arango

    main

    Overload Control is a mechanism designed to handle time-bound requests by setting a maximum server-side queuing time. When you use a controlled execution context, you can specify a max_queue_time_seconds limit. If a request's queuing time on the ArangoDB server exceeds this limit, the server will reject the request.

    This allows applications to react to server overloads rather than waiting indefinitely for requests that are already too late to be useful.

    Key behaviors:

    • Rejection: Requests exceeding the limit are rejected with an error.
    • Monitoring: Every response from ArangoDB includes the most recent request queuing/dequeuing time, which is exposed via the last_queue_time property.
    • Bypassing: Setting max_queue_time_seconds to 0 or a non-numeric value causes ArangoDB to ignore the overload control header.
    from arango import ArangoClient
    
    client = ArangoClient()
    db = client.db('test', username='root', password='passwd')
    
    # Create a controlled execution context with a 7.5 second limit
    controlled_db = db.begin_controlled_execution(max_queue_time_seconds=7.5)
    
    # Use controlled_db.aql or controlled_db.collection('name') to perform operations
    controlled_db.collection('students').insert({'_key': 'Neal'})
  6. Manage users and permissions via the _system database

    main

    Most user and permission management operations require administrative privileges and must be performed by connecting to the _system database (typically as the root user).

    # Connect to "_system" database as root user.
    sys_db = client.db('_system', username='root', password='passwd')
  7. How transactions work in python-arango

    main

    Transactions in python-arango allow you to group requests to the ArangoDB server into a single, ACID-compliant logical unit of work.

    There are two primary ways to handle transactions:

    1. The Transaction API: Uses a TransactionDatabase wrapper. You explicitly begin a transaction, perform operations through specialized wrappers (like txn_db.aql or txn_db.collection()), and must manually call commit_transaction() or abort_transaction().
    2. JavaScript Transactions: Uses db.execute_transaction() to run raw JavaScript code directly on the server. This is useful for complex logic that requires server-side execution.

    Important Version Note: Since version 5.0.0, the transaction API is not backward-compatible with older versions. Context managers are no longer supported; you must manually commit your transactions. Additionally, results are returned immediately instead of returning job objects.

    from arango import ArangoClient
    
    client = ArangoClient()
    db = client.db('test', username='root', password='passwd')
    
    # Method 1: Transaction API (Manual commit/abort)
    txn_db = db.begin_transaction(read='students', write='students')
    txn_col = txn_db.collection('students')
    txn_col.insert({'_key': 'Abby'})
    txn_db.commit_transaction()
    
    # Method 2: JavaScript Transaction (Raw JS code)
    db.execute_transaction(
        command='function() { ... }', 
        params={'key': 'val'}, 
        read='students', 
        write='students'
    )
  8. Define a custom HTTP client

    main

    Python-arango allows you to provide your own HTTP client implementation for sending requests to the ArangoDB server. This is useful if you need to implement custom logic such as automatic retries, custom headers, disabled SSL verification, or specialized logging.

    To create a custom client, you must inherit from arango.http.HTTPClient and implement two abstract methods:

    1. create_session(self, host): Must return a session instance (e.g., a requests.Session) for the given host. These sessions are managed and stored by the client.
    2. send_request(self, session, method, url, params=None, data=None, headers=None, auth=None): Must use the provided session to execute the HTTP request and return a fully populated instance of arango.response.Response.
    from arango.http import HTTPClient
    from arango.response import Response
    
    class CustomHTTPClient(HTTPClient):
        def create_session(self, host):
            # Return a session object (e.g., requests.Session)
            pass
    
        def send_request(self, session, method, url, params=None, data=None, headers=None, auth=None):
            # Execute request and return an arango.response.Response instance
            pass
  9. How cursors work in python-arango

    main

    Many operations in python-arango, such as executing AQL queries via db.aql.execute(), return a cursor object. Cursors are used to batch network communication between the ArangoDB server and the client. Instead of fetching all results at once, the client fetches results in batches (defined by batch_size).

    By default, python-arango uses a "just-in-time" fetching strategy: when you iterate over the cursor or call .next(), the client automatically sends an HTTP request to the server to fetch the next batch if the current one is depleted. You can also take manual control of the fetching process using .fetch() and .pop().

    from arango import ArangoClient
    
    client = ArangoClient()
    db = client.db('test', username='root', password='passwd')
    
    # Default just-in-time batching via iteration
    cursor = db.aql.execute('FOR doc IN students RETURN doc', batch_size=1)
    result = [doc for doc in cursor]
  10. Understand the python-arango exception hierarchy

    main

    All exceptions in python-arango inherit from arango.exceptions.ArangoError. This base class is split into two main categories depending on where the error originated:

    1. arango.exceptions.ArangoServerError: Raised when ArangoDB returns a non-2xx HTTP response. These exceptions contain detailed information about the server's response, including error codes, HTTP status, and the request/response objects.
    2. arango.exceptions.ArangoClientError: Raised by the python-arango client itself (e.g., due to malformed input or local validation failures). These do not contain ArangoDB error codes or HTTP response details; only the message attribute is populated.
  11. Manage graph components via the Graph API wrapper

    main

    Once you have obtained a graph object using db.graph('graph_name'), you can interact with its constituent parts using specialized API wrappers:

    • Vertex Collections: Use school.vertex_collection('collection_name') to get a wrapper for a vertex collection within the graph.
    • Edge Collections: Use school.edge_collection('collection_name') to get a wrapper for an edge collection within the graph.

    These wrappers allow you to perform standard collection operations like insert(), has_vertex_collection(), and create_vertex_collection() specifically within the context of the graph structure.

    from arango import ArangoClient
    
    client = ArangoClient()
    db = client.db('test', username='root', password='passwd')
    school = db.graph('school')
    
    # Accessing components
    teachers = school.vertex_collection('teachers')
    lectures = school.vertex_collection('lectures')
    teach = school.edge_collection('teach')
    
    # Using the wrappers to insert data
    teachers.insert({'_key': 'jon', 'name': 'Professor jon'})
    lectures.insert({'_key': 'CSC101', 'name': 'Introduction to CS'})
    teach.insert({'_from': 'teachers/jon', '_to': 'lectures/CSC101'})
  12. Manage Foxx microservices with python-arango

    main

    Python-arango provides a Foxx API wrapper to manage microservices in ArangoDB. Foxx allows you to define custom HTTP endpoints to extend ArangoDB's REST API.

    Warning: Foxx microservice features are no longer available in ArangoDB 4.0.

    To access Foxx functionality, connect to a database and use the .foxx attribute on the database object.

    from arango import ArangoClient
    
    client = ArangoClient()
    db = client.db('_system', username='root', password='passwd')
    foxx = db.foxx