Vautra Python SDK
Python SDK for Vautra projects, buckets, and object storage.
The SDK signs every request and sends it to https://app.vautra.com/api by default. Keep the secret access key on a trusted server; it is a credential, not a public identifier.
Requirements
- Python 3.9 or newer.
requests2.31 or newer (installed automatically).
Installation
pip install vautra-sdk
The distribution is vautra-sdk; the import name is vautra. The npm package of
the same name is the separate Node.js SDK.
Authentication
Create an access key in the Vautra dashboard, then build one client and reuse it — each client owns a connection pool:
from vautra import Vautra
vautra = Vautra(
access_key_id="...",
secret_access_key="...",
)
Credentials fall back to the VAUTRA_ACCESS_KEY_ID and VAUTRA_SECRET_ACCESS_KEY environment variables, and api_url to VAUTRA_API_URL, when the corresponding argument is omitted:
from vautra import Vautra
with Vautra() as vautra: # reads the environment
page = vautra.projects.list()
Every request carries a fresh nonce, including retries, so signed headers are never replayed. Access-key permissions and project or bucket restrictions are enforced by the Vautra backend.
Invalid configuration raises VautraConfigError immediately, before any request is sent. api_url must use https:// unless it points at a loopback address, so signed credentials never travel over plaintext.
Client options
| Option | Default | Description |
|---|---|---|
access_key_id |
$VAUTRA_ACCESS_KEY_ID |
Required. |
secret_access_key |
$VAUTRA_SECRET_ACCESS_KEY |
Required. Never logged; the client redacts it in repr(). |
api_url |
$VAUTRA_API_URL or https://app.vautra.com/api |
Must be https:// for remote hosts. |
timeout |
30.0 |
Seconds, for non-upload requests. Use 0 or None to disable. |
session |
new session | Supply your own requests.Session to control proxies or TLS verification. |
Every method also accepts a per-call timeout= override and a cancel_event= (a threading.Event).
Vautra is a context manager, and close() releases the connection pool:
with Vautra(access_key_id="...", secret_access_key="...") as vautra:
...
Object keys
Vautra object keys are flat file names, not S3-style paths:
- No
/or\separators —documents/report.pdfis rejected. - Maximum 255 bytes (UTF-8), no control characters, no trailing period.
- The key must end in a supported extension.
Supported extensions are currently: txt, csv, json, xml, html, css, js, ts, md, pdf, png, jpg, jpeg, gif, webp, svg, zip, gz, doc, docx, xlsx, pptx, mp3, mp4, webm, wav, ogg. Files whose contents do not match their extension are rejected on upload.
Invalid keys raise VautraError immediately, before an upload session is created.
Projects
page = vautra.projects.list(
page=1,
page_size=20,
search="production",
key_management="managed",
)
project = vautra.projects.get("project-id")
List methods return {"data": [...], "meta": {"page", "pageSize", "total", "totalPages"}}.
Buckets
page = vautra.buckets.list(project_id="project-id", page=1, page_size=20)
bucket = vautra.buckets.get("bucket-id")
created = vautra.buckets.create(
project_id="project-id",
name="documents",
versioning_enabled=True,
)
Bucket deletion is intentionally not exposed by the SDK.
List objects
page = vautra.objects.list("bucket-id", page=1, page_size=20, search="invoice")
Upload objects
For large local files, pass a path. The SDK reads only the active chunks instead of loading the whole file into memory:
obj = vautra.objects.upload(
bucket_id="bucket-id",
key="movie.mp4",
body="C:/videos/movie.mp4", # str, pathlib.Path, or {"path": ...}
content_type="video/mp4",
)
For content already in memory:
vautra.objects.upload(
bucket_id="bucket-id",
key="hello.txt",
body=b"Hello from Vautra",
content_type="text/plain",
)
When content_type is omitted, Vautra derives the stored MIME type from the key's extension.
Supported body types
| Body | Behaviour |
|---|---|
bytes, bytearray, memoryview |
Used directly. |
str |
Encoded as UTF-8. |
pathlib.Path, os.PathLike, {"path": "..."} |
Opened and read by range; memory stays flat. |
| A seekable binary file object | Read by range from its current position. The SDK does not close a handle it did not open. |
A non-seekable stream (pipe, socket, generator of bytes) |
Spooled to a temporary file so failed parts can be retried, then cleaned up. |
Any object with size and read(start, end) |
Used as a random-access source. |
A stream cannot be rewound, so a failed part could not otherwise be retried. Spooling keeps memory flat regardless of stream size. Prefer a path when the data is already on disk.
Text-mode file objects are rejected — open files with "rb".
Upload options
import threading
cancel = threading.Event()
vautra.objects.upload(
bucket_id="bucket-id",
key="archive.zip",
body="./archive.zip",
concurrency=2, # 1-4
max_attempts=3, # 1-5
attempt_timeout=180.0, # seconds per request
cancel_event=cancel,
on_started=lambda upload_id: print("session", upload_id),
on_progress=lambda p: print(p["stage"], p["loadedBytes"], p["totalBytes"]),
)
Progress stages are starting, uploading, finalizing, and success. loaded_bytes never goes backwards and a retried part is counted once.
Part and completion requests retry network failures, HTTP 408, 429, and 5xx. Retry delays are one second then three seconds. Other 4xx responses are terminal, as are errors raised locally by the SDK.
If an upload fails after its session is created, the SDK makes a best-effort request to cancel and clean up that session. Secure cross-process resume is not supported.
SDK access keys work only with Vautra-managed projects and their buckets. Customer-managed projects are intentionally excluded from SDK access-key scopes.
Upload status and cancellation
status = vautra.objects.upload_status("upload-id")
vautra.objects.cancel_upload("upload-id")
upload_status() is for inspection only; it does not enable resume.
To cancel a running upload, set the threading.Event you passed as cancel_event:
import threading
cancel = threading.Event()
worker = threading.Thread(
target=vautra.objects.upload,
kwargs={
"bucket_id": "bucket-id",
"key": "large.zip",
"body": "./large.zip",
"cancel_event": cancel,
},
)
worker.start()
cancel.set()
The upload raises VautraCancelledError, and the session is cleaned up. An already-set event raises before any request is sent.
Because requests is synchronous, cancellation takes effect between parts and between retry attempts — it does not interrupt a request already on the wire. attempt_timeout bounds that window.
Download objects
Return the object as bytes:
data = vautra.objects.download("object-id")
Buffered downloads are capped at 256 MiB so a large object cannot exhaust memory. Pass max_bytes to change the cap, or 0 to disable it. Objects above the cap raise VautraError with status 413.
Write directly to a file, which streams and is not capped:
vautra.objects.download("object-id", destination="./report.pdf")
The file is written to a temporary sibling and renamed into place, so an interrupted download never leaves a truncated file at destination.
Or consume the stream yourself:
with vautra.objects.download_stream("object-id") as stream:
print(stream.content_type, stream.content_length)
for chunk in stream:
sink.write(chunk)
Downloads through the SDK are available only for Vautra-managed projects.
Delete objects
vautra.objects.delete("object-id")
Deletion is subject to access-key permissions and backend object-state rules.
Errors
Every SDK error derives from VautraError:
from vautra import VautraError
try:
vautra.buckets.get("missing-bucket")
except VautraError as error:
print(error.status, error.code, error.message)
| Exception | Raised when |
|---|---|
VautraError |
The API returned a failure. Carries status, code, details. |
VautraConfigError |
Client configuration is unusable. Raised before any request. |
VautraTimeoutError |
A request exceeded its time budget (status 408). |
VautraConnectionError |
The API could not be reached (status 0). |
VautraCancelledError |
The caller's cancel_event was set. |
Errors also expose retryable, which the upload retry loop uses to avoid burning attempts on failures that would repeat identically.
The SDK never follows redirects: signed credentials are not forwarded to another host, and an unexpected 3xx surfaces as a VautraError with code unexpected_redirect.
Thread safety
A Vautra client is safe to share across threads. Uploads use a bounded worker pool internally and read bodies under a lock.
Development
python -m venv .venv && .venv/Scripts/activate # or source .venv/bin/activate
pip install -e ".[dev]"
pytest
ruff check . && mypy
The test suite runs against a mock Vautra API whose signature verification is a port of the backend's verifier, so a passing test means the SDK interoperates with the real service rather than with a permissive stub.
To try a real upload:
python examples/upload_file.py ./examples/sample.txt --bucket-id BUCKET --key sample.txt
License
MIT. See LICENSE.
Release files for vautra-sdk 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| vautra_sdk-1.0.0.tar.gz | 43.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| vautra_sdk-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 75.5 kB
Release files / vautra_sdk-1.0.0.tar.gz
| Download URL | vautra_sdk-1.0.0.tar.gz |
|---|---|
| Size | 43.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
97ce5200c4419e5687ec4e443139a1f4215e7acfab97e404f80de9d9339aaa40
|
|
BLAKE2b-256 checksum How to use checksums |
aa253c56ea6360629c929ddcce65680ba338bb6314d1c9d4e49a12df2300fa4b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|
Release files / vautra_sdk-1.0.0-py3-none-any.whl
| Download URL | vautra_sdk-1.0.0-py3-none-any.whl |
|---|---|
| Size | 32.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5a312a2ac76c7cfb464d9ac08628689078357cae6078dd8d4c069fef2324fe1f
|
|
BLAKE2b-256 checksum How to use checksums |
fcf0e8926d22984edbce5ea9e788255703ee98d9d7d0731e51c390956927dc3c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|