Metadata-Version: 2.5
Name: nerdstack-ark
Version: 1.0.1
Summary: Official Python SDK for Ark storage, with sync, async, and S3-compatible access.
Project-URL: Homepage, https://ark.nerdstackgrp.com
Project-URL: Documentation, https://github.com/joshhumphrey02/ark-sdk/tree/master/packages/ark-py#readme
Project-URL: Repository, https://github.com/joshhumphrey02/ark-sdk
Project-URL: Issues, https://github.com/joshhumphrey02/ark-sdk/issues
Author: Nerdstack
License-Expression: MIT
License-File: LICENSE
Keywords: ark,django,fastapi,flask,s3,storage,upload
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: AsyncIO
Classifier: Framework :: Django
Classifier: Framework :: FastAPI
Classifier: Framework :: Flask
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx<1,>=0.27
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.3; extra == 'dev'
Requires-Dist: ruff>=0.9; extra == 'dev'
Requires-Dist: twine>=6.0; extra == 'dev'
Provides-Extra: django
Requires-Dist: django>=4.2; extra == 'django'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.110; extra == 'fastapi'
Provides-Extra: flask
Requires-Dist: flask>=2.3; extra == 'flask'
Provides-Extra: s3
Requires-Dist: boto3<2,>=1.35; extra == 's3'
Description-Content-Type: text/markdown

# Ark for Python

The official Python SDK for [Ark](https://ark.nerdstackgrp.com) storage. It is
framework-independent and provides:

- `Ark` for Django, Flask, Celery, scripts, and synchronous workers.
- `AsyncArk` for FastAPI, Starlette, aiohttp, and async workers.
- Memory-bounded single and multipart uploads.
- Typed result models and one normalized `ArkError` exception.
- Optional access through Ark's S3-compatible endpoint using boto3.

## Install

```bash
pip install nerdstack-ark
```

For S3-compatible access:

```bash
pip install "nerdstack-ark[s3]"
```

Python 3.10 or newer is required.

## Synchronous usage

```python
import os
from ark_py import Ark

with Ark(os.environ["ARK_API_TOKEN"]) as ark:
    folder = ark.folders.create("Product Media")
    file = ark.files.upload(
        "./hero.mp4",
        folder_id=folder.id,
        content_type="video/mp4",
    )
    download_url = ark.files.get_download_url(file.id, expires_in_seconds=600)
    print(download_url)
```

Filesystem paths stream directly from disk. A file-like object is also
accepted; provide `size` and `filename` when it is not seekable:

```python
file = ark.files.upload(
    request.stream,
    size=int(request.headers["content-length"]),
    filename="upload.bin",
)
```

The stream must produce exactly the declared number of bytes. Ark aborts an
incomplete server-side session if the transfer fails, underflows, or overflows.

## Asynchronous usage

```python
import os
from ark_py import AsyncArk

async with AsyncArk(os.environ["ARK_API_TOKEN"]) as ark:
    file = await ark.files.upload("./hero.mp4", content_type="video/mp4")
    usage = await ark.usage()
    print(file.id, usage.storage.used_bytes)
```

`AsyncArk.files.upload` accepts paths, ordinary binary files, and
`AsyncIterable[bytes]`. Async iterables require an exact `size` and `filename`.

## Files, folders, images, and sessions

```python
page = ark.files.list(folder_id=folder.id, limit=50)
file = ark.files.get(page.data[0].id)
ark.files.move(file.id, folder_id=None)
ark.files.delete(file.id)

folders = ark.folders.list(parent_id=None)
ark.folders.rename(folder.id, "Campaign Media")

image_url = ark.images.url(file.id)
signed_url = ark.images.signed_url(file.id, expires_in_seconds=600)

session = ark.create_client_session(ttl_seconds=900)
# Hand session.token to @nerdstackgrp/ark-client in the browser.
```

## S3-compatible access

```python
import os
from ark_py import create_s3_client

s3 = create_s3_client(
    access_key_id=os.environ["ARK_ACCESS_KEY_ID"],
    secret_access_key=os.environ["ARK_SECRET_ACCESS_KEY"],
)

s3.put_object(Bucket="product-media", Key="hero.jpg", Body=image_bytes)
objects = s3.list_objects_v2(Bucket="product-media", Prefix="photos/")
```

These must be Ark-issued S3 credentials. The helper configures SigV4 and
path-style addressing for `https://ark.nerdstackgrp.com/s3`.

## Errors

```python
from ark_py import ArkError

try:
    ark.files.get("missing")
except ArkError as error:
    print(error.code, error.status, error.request_id, error.retryable)
```

## Framework examples

Complete examples live in [`examples/`](examples):

- Django upload view and application lifecycle.
- Flask application factory and upload route.
- FastAPI lifespan management and `UploadFile` streaming.

Keep `ARK_API_TOKEN` in server-side environment configuration. Never expose it
to templates, frontend bundles, mobile apps, logs, or error responses.

## Development

```bash
python -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest
.venv/bin/ruff check .
.venv/bin/mypy
.venv/bin/python -m build
.venv/bin/twine check dist/*
```

## License

MIT © Nerdstack.
