Skip to main content

python-openarch-api

Python client for the REST API of Hyland OpenArch, an open source project that federates unstructured, AI-ready data from all sources across an organization and makes it available to AI services and agents while always respecting permissions. OpenArch can be self-managed and used with your own LLMs and choice of AI services. Sync and async, with Pydantic v2 models.

  • Every operation of docs/openapi/openarch-api.yaml: documents by id and path (with conditional writes and upsert), query / advanced / named / terms aggregation / vector search, download, users and groups, repository model and security policies (v1 and v2), vocabularies, upload.
  • Pydantic v2 models generated from the spec, plus hand-written OpenArchDocument and OpenArchQueryResult: documents carry dynamic cin_* properties the generated types do not type (the same choice content-lake-app makes in Java).
  • OpenArchClient (sync) and AsyncOpenArchClient (async), on httpx. The sync client is generated from the async one, so the two never drift.
  • Basic auth (a local OpenArch), bearer token (the cloud CIC) — a string or a function returning the current one — or any httpx.Auth.

Status: alpha (0.1.0). Written against the spec generated by running OpenArch (docs/openapi/openarch-api.yaml), first from main aa90475b (2026-10-13, 12.0-SNAPSHOT). The spec was regenerated from main 34caff31 (2026-10-19), the version that added the BasicAuth security scheme, its only change: until then the spec declared only the bearer token of the cloud CIC (Hyland Content Innovation Cloud). Checked again on 2026-10-21 against 28f4b833 (unchanged); see docs/openapi/README.md. Unit-tested with mocks and tested against a local OpenArch in Docker (tests/test_live.py).

Install

uv pip install python-openarch-api

For development with the source, install from a clone instead: uv pip install -e ".[dev]" (see Development).

Use

Every method, model and error is described in the API reference, docs/api.md.

from python_openarch_api import OpenArchClient, OpenArchDocument

with OpenArchClient("http://localhost:8080", username="admin", password="password") as oa:
    print(oa.hello(protected=True))

    # Query (HXQL)
    result = oa.query("SELECT * FROM SysContent WHERE cin_sourceId = 'repo-1'", limit=50)
    for doc in result.documents:
        print(doc.sys_id, doc.sys_name, doc.cin_id, doc.properties)

    # Next page: pass the cursor back
    more = oa.query("SELECT * FROM SysContent WHERE cin_sourceId = 'repo-1'", limit=50,
                    search_after=result.next_search_after)

    # Create a document carrying source-system fields (needs the CinRemote mixin)
    doc = OpenArchDocument(sys_primary_type="SysFile", sys_name="report.pdf",
                           cin_id="node-1", cin_source_id="repo-1").with_cin_remote()
    created = oa.create_document_by_path("/alfresco-sync", doc)

    # Partial update, only if the title is still the old one
    oa.patch_document(created.sys_id, [{"op": "replace", "path": "/sys_title", "value": "Report"}],
                      if_='content.sys_title == "report.pdf"')

Async:

from python_openarch_api import AsyncOpenArchClient

async with AsyncOpenArchClient("https://openarch.example.com", token=get_access_token) as oa:
    doc = await oa.get_document("a1b2c3")

Documents and dynamic properties

OpenArchDocument has the schema's sys_* fields (snake_case in Python, e.g. sys_primary_type; their wire names on the way out) and the CinRemote fields cin_id, cin_source_id, cin_paths, cin_ingest_properties, cin_ingest_property_names, cin_read, cin_deny. Any other property (repository-model fields, sysembed_*) is kept as is:

doc.properties               # {"my_customField": 42, ...}  (wire names)
doc.get("cin_sourceId")      # any property by wire name
doc.to_json()                # request body: wire names, None left out

OpenArch rejects a document with cin_* fields unless sys_mixinTypes includes CinRemote; with_cin_remote() adds it.

Binary content

A blob property points at its content by uploadId. Send the content in the same request (the part name is yours to pick), or upload it first:

oa.create_document_by_path("/docs", {"sys_primaryType": "SysFile", "sys_name": "a.txt",
                                     "sysfile_blob": {"uploadId": "f1"}},
                           files={"f1": ("a.txt", data, "text/plain")})

up = oa.upload(data, file_name="a.txt", mime_type="text/plain")
oa.create_document_by_path("/docs", {"sys_primaryType": "SysFile", "sys_name": "a.txt",
                                     "sysfile_blob": {"uploadId": up.id}})

oa.download(doc_id, "sysfile_blob/a.txt")    # -> bytes

Writes

update_document, patch_document, move (and the _by_path ones) take condition= (an HXQL predicate) or if_= (an expression), user_change=False for technical updates that should not bump sys_ugen, and on PUT upsert=True to create the document when it does not exist.

Model and security policies: v1 and v2

get_model / set_model / get_security_policies / set_security_policies are the v1 API. The _v2 methods return and take a version for optimistic locking: read with get_*_v2, change, and send the same object back with set_*_v2.

Repository

The HXCS-REPOSITORY header is sent on every request (repository="default"); pass repository= to the client or to a call to use another one.

Errors

Non-2xx answers raise OpenArchError (status_code, error = the parsed RepositoryErrorResponse), or its subclasses OpenArchAuthError (401/403), OpenArchNotFoundError (404), OpenArchConflictError (409: a set_*_v2 with a stale version) and OpenArchPreconditionError (412: a condition / if_ that did not match, or checkin of a non-versionable document).

Development

Create and activate a virtual environment, then install the package with the dev extra.

Linux / macOS:

uv venv venv-3.14 --python 3.14
source venv-3.14/bin/activate
uv pip install -e ".[dev]"
python -m pytest

Windows (PowerShell or Command Prompt):

uv venv venv-3.14 --python 3.14
venv-3.14\Scripts\activate
uv pip install -e ".[dev]"
python -m pytest

With the virtual environment active, the same on every platform:

python scripts/generate_models.py   # after updating docs/openapi/openarch-api.yaml
python scripts/unasync.py           # after editing python_openarch_api/_async/client.py

The dev extra (-e ".[dev]") is needed to run the tests and the scripts: it brings pytest, PyYAML (a test reads the spec) and the pinned datamodel-code-generator. A plain uv pip install -e . installs only httpx and Pydantic.

  • docs/openapi/openarch-api.yaml — the spec, downloaded from a running OpenArch (it ships no static spec); docs/openapi/README.md says how to regenerate it.
  • python_openarch_api/models/generated.py — generated by datamodel-code-generator (pinned); do not edit.
  • python_openarch_api/_async/client.py — the client; edit this one.
  • python_openarch_api/_sync/client.py — generated from it; a test fails if it is stale.
  • A test checks that every operationId in the spec has a client method.
  • tests/test_live.py runs against a real OpenArch when OPENARCH_URL is set (it creates and deletes a folder at the root). OpenArch's root docker-compose.yml leaves the data dir unwritable, so every upload is a 500: start openarch-app with NUXEO_DATA_DIR=/tmp, as OpenArch's own README and CI do.

Tests

pytest collects 23 tests in total: 16 unit tests (tests/test_client.py, with mocks, no server) and 7 live tests (tests/test_live.py), which are skipped unless OPENARCH_URL is set. To run the live tests against a running OpenArch, set OPENARCH_URL in the shell where the virtual environment is active. Use http://localhost:8080 for OpenArch's own default port, or http://localhost:8088 for the OpenArch of KG Spaces Deployment (its OPENARCH_PORT, 8088 by default).

Linux / macOS:

OPENARCH_URL=http://localhost:8080 python -m pytest tests/test_live.py

Windows (PowerShell):

$env:OPENARCH_URL = "http://localhost:8080"
python -m pytest tests/test_live.py

Windows (Command Prompt):

set OPENARCH_URL=http://localhost:8080
python -m pytest tests/test_live.py

Without tests/test_live.py, python -m pytest runs the unit tests and the live tests together.

OPENARCH_USER / OPENARCH_PASSWORD set the Basic auth user; they default to the admin user of the local openarch-app's openarch-users.yml. Set them the same way as OPENARCH_URL.

Where the spec and the server differ

The client follows the server where the generated spec is short of it:

  • Multipart document writes: the spec shows a placeholder part (main1234); any name works, as long as a blob property references it by uploadId.
  • nextSearchAfter: the query schemas refer to it but QueryResult does not declare it; OpenArchQueryResult.next_search_after reads it.
  • StringTermsBucket has no properties in the spec; TermsBucket types key and doc_count.
  • Responses the spec leaves untyped (named query list, v1 security policies) are returned as parsed JSON.
  • download_url needs a blob provider with pre-signed URLs (S3); the local filesystem store answers 501.

License

Apache-2.0, as is OpenArch, from which docs/openapi/openarch-api.yaml is generated.

Metadata

Release files for python-openarch-api 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for python-openarch-api 0.1.0
File Size Uploaded Provenance
python_openarch_api-0.1.0.tar.gz 59.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for python-openarch-api 0.1.0
File Interpreter ABI Platform
python_openarch_api-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 93.4 kB

Release files / python_openarch_api-0.1.0.tar.gz

Download URL python_openarch_api-0.1.0.tar.gz
Size 59.4 kB
Tags Source
SHA-256 checksum
How to use checksums
9067e27b993b856269d30c19582bcaac7c071bf8f0f032c80a9c7b79f61821f7
BLAKE2b-256 checksum
How to use checksums
ce7ebc78d7aaedf1cc1972f581bca84b456f5c4a3327b668e99e670fbf839064
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / python_openarch_api-0.1.0-py3-none-any.whl

Download URL python_openarch_api-0.1.0-py3-none-any.whl
Size 34.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
88faa48cc8ad2dbf9346d1920602d071d903501681fc3281c28dc5e7653cf88c
BLAKE2b-256 checksum
How to use checksums
252a3edbd4afeacbd1c6e4ab7a508f4e879fe05b70f9fa9553128bc9ea2b7d3e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for python-openarch-api 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page