> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blobhub.io/llms.txt
> Use this file to discover all available pages before exploring further.

# ONNX

> blobhub.types.onnx: upload, list, download and inspect the model in an ONNX blob revision

`blobhub.types.onnx.Onnx` is the typed module for `blobhub.model.onnx` blobs. Each revision of such a blob holds one
model, which you upload as a `.onnx` file and the platform processes into three artifacts.

```python theme={null}
import blobhub
from blobhub.types.onnx import Onnx

hub = blobhub.connect(anonymous=True)
revision = hub.blob("onnx-vision-models", "super-resolution").revision()

model = Onnx(revision)          # or revision.typed()
model.artifacts()               # [Artifact(path='model.json', size=…), Artifact(path='model.onnx', …), …]
path = model.download()         # model.onnx, cached under ~/.cache/blobhub
graph = model.topology()        # the parsed model graph, without its weights
```

`Onnx(revision)` raises `TypeMismatch` when the revision's blob is not an ONNX blob.

## Artifacts

`model.artifacts()` sends [`describe`](/blob-types/onnx/describe) and returns a list of `Artifact(path, size)`. A
processed upload yields three:

| `path` | What it is |
| :- | :- |
| `model.tar.gz` | The archive as uploaded. |
| `model.onnx` | The model, extracted by the platform. |
| `model.json` | The model's graph without its weights, which `topology()` parses. |

The list is empty until an upload has been processed.

## Download

`model.download(path="model.onnx", *, dest=None)` downloads one artifact and returns its local `Path`.

```python theme={null}
model.download()                                    # model.onnx into the cache
model.download("model.tar.gz", dest="./model.tar.gz")
model.download("model.json", dest="exports/")       # exports/model.json; the folder is created
```

* **`dest=None` uses the cache.** Files land in `~/.cache/blobhub/revisions/<revision id>/`, or in the same layout
  under `$XDG_CACHE_HOME/blobhub` when that variable holds an absolute path.
* **`dest` is a folder or a file.** An existing folder, or a string ending in `/`, receives the artifact under its
  own name; anything else is the file path to write. A file written to `dest` is never cached.
* **The file appears complete or not at all.** The bytes go to a temporary file next to the target, which replaces
  the target only once its size matches the artifact's.
* **An artifact the revision does not hold** raises `NotFound` with `error` `artifact_not_found` and `status`
  `None`, before any download is attempted. That is what a draft whose upload is still being processed gives you.
* **Up to 4 MiB, the artifact comes in one request** through [`download`](/blob-types/onnx/download). Above that it
  comes in ranged parts over presigned URLs, through
  [`initiate_download`](/blob-types/onnx/multipart-download), each part written at its offset.

The SDK never unpacks an archive. `download()` fetches the `model.onnx` the platform already extracted.

### The cache

A cached copy is reused only for a **committed** revision, whose content can no longer change. Before reusing it,
`download()` reads the revision again and checks that it is still committed and that the copy was taken from that
exact state: a revision that was reopened, changed and committed again is downloaded afresh. A draft's artifacts
are downloaded every time.

The cache is never pruned. Delete `~/.cache/blobhub` whenever you like.

## Topology

`model.topology()` downloads `model.json` (cached like any artifact) and returns it parsed as a `dict`: the model's
graph without its weights. It is how you look at a large model without fetching the model itself.

## Upload

`model.upload(file, *, timeout=600.0)` uploads a local `.onnx` file to the revision, waits until the platform has
processed it, and returns the completed [`Operation`](/sdk/blobs-and-revisions#operations).

```python theme={null}
from pathlib import Path

blob = hub.blob("acme", "super-resolution")
revision = blob.revision()
if revision.phase != "draft":                      # a committed revision takes no writes
    revision = blob.create_revision("retrained")

model = Onnx(revision)
model.upload("super_resolution.onnx")
assert model.download().read_bytes() == Path("super_resolution.onnx").read_bytes()
revision.commit("v2")                               # freezes it; its downloads are cached from now on
```

That needs a credential that can write to the blob, so `hub` here comes from `blobhub.connect()`, not
`connect(anonymous=True)`.

What `upload()` does:

1. **Checks the file.** It must exist (`FileNotFoundError`), end in `.onnx` and not be empty (`ValueError`).
2. **Packs it.** It writes `model.tar.gz` in a temporary folder, holding exactly one regular file named
   `model.onnx`. The platform's processing refuses an archive holding anything else.
3. **Uploads it.** An archive of up to 4 MiB goes in one request, [`upload`](/blob-types/onnx/upload). A larger one
   goes in 10 MiB parts over presigned URLs: [`initiate_upload`, the part uploads, then
   `complete_upload`](/blob-types/onnx/multipart-upload). If anything fails after `initiate_upload`, the SDK sends
   `cancel_upload` before raising.
4. **Waits** on the upload's operation until it is `completed`. If processing fails, because the file does not parse
   as ONNX, it raises `OperationFailed` with `error` `upload_failed`. After `timeout` seconds it raises
   `WaitTimeout`, and the processing carries on.

```mermaid theme={null}
sequenceDiagram
  participant O as Onnx.upload
  participant A as api.blobhub.io
  participant S as presigned storage
  O->>O: check the file, pack model.tar.gz
  alt archive up to 4 MiB
    O->>A: upload, with the archive as the body
    A-->>O: operation_id
  else larger
    O->>A: initiate_upload, with the size
    A-->>O: operation_id and a part plan
    O->>S: PUT each part, keep its ETag
    O->>A: complete_upload, with the ETags
  end
  O->>A: GET /operations/{id} until completed or failed
```

The platform's own checks surface as errors:

| Error | When |
| :- | :- |
| `Conflict` `revision_not_writable` | The revision is committed. Upload to a draft. |
| `CommandError` `limit_exceeded` | The archive is larger than the blob's `space_per_revision` limit. |
| `PermissionDenied` | The credential cannot write to the blob, or the client is anonymous. |

**Uploads are writes, so they are not retried** after a failure that may have reached the platform; see
[Errors and retries](/sdk/errors#retries). A part's own `PUT` to storage is retried, because repeating it is
harmless.

## See also

* [Notebooks](/sdk/notebooks) — three notebooks download public models; the fourth uploads one.
* [Upload Model](/blob-types/onnx/upload), [Multipart Upload](/blob-types/onnx/multipart-upload),
  [Describe Model](/blob-types/onnx/describe), [Download Model](/blob-types/onnx/download) and
  [Multipart Download](/blob-types/onnx/multipart-download) — the REST commands underneath.
* [Get Operation](/rest-api/operations/get-operation) — what `upload()` waits on.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.