> For the complete documentation index, see [llms.txt](https://docs.unitlab.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.unitlab.ai/api-sdk-cli/get-started/python-sdk-quickstart.md).

# Python SDK quickstart

Upload an image folder with the Unitlab Python SDK. Create a project, wait for processing, and verify each Data Unit with a complete two-image example.

Upload two images to a new project, wait for processing, and list the resulting Data Units. This example uses Unitlab Python SDK **3.1.3**.

## Before you start

1. [Install the SDK](/api-sdk-cli/get-started/install-the-python-sdk-and-cli.md) and [configure your API key](/api-sdk-cli/get-started/authentication-and-configuration.md).
2. Prepare two valid JPG images named `road.jpg` and `crossing.jpg`. The names below are examples; use your own images.
3. Save the following script as `upload.py` next to the `images` folder.

```
road-scenes/
├── upload.py
└── images/
    ├── road.jpg
    └── crossing.jpg
```

The script uploads only `images/`. It does not upload the script, infer groups, or create annotations.

## 1. Create the project and upload

```python
from pathlib import Path
from unitlab import UnitlabClient

source = Path(__file__).resolve().parent / "images"
client = UnitlabClient()
try:
    project = client.projects.create("Road scenes")
    print("project_id:", project.id)

    batch = project.upload(source)
    print("batch_queue_id:", batch.batch_queue_id)
    print("accepted:", batch.uploaded)
    print("local_failures:", len(batch.failed))

    for failure in batch.failed:
        print("upload_error:", failure.path, failure.error)

    if not batch.batch_queue_id:
        raise SystemExit("No Batch Queue was created. Check the upload errors.")

    status = batch.wait(timeout=1800)
    print("processing_failures:", status.failed)

    for unit in project.data_units(batch_queue=batch.batch_queue_id):
        print(unit.id, unit.kind, unit.name, unit.status)
finally:
    client.close()
```

Run it from the `road-scenes` directory:

```bash
python upload.py
```

Each run creates a new project. To use an existing project, replace `client.projects.create("Road scenes")` with `client.projects.get("PROJECT_ID")`, using its actual ID. Keep the printed project and Batch Queue IDs so you can inspect the same upload after a timeout.

## 2. Check the result

For these two valid images in a new project, verify:

| Check                          | Expected result                                        |
| ------------------------------ | ------------------------------------------------------ |
| Accepted upload requests       | `accepted: 2`                                          |
| Local upload failures          | `local_failures: 0`                                    |
| Server processing failures     | `processing_failures: 0`                               |
| Data Units in this Batch Queue | `road.jpg` and `crossing.jpg`, each as a separate item |
| Project Data view              | Both images open correctly                             |

`batch.wait()` waits until there are no active processing items. It can finish with failures, so check both the local failures and `status.failed`. An upload completing does not mean its items have been annotated or approved.

For other file types, video frame rates, CSV settings, local file lists, and recovery, continue to [Project uploads](/api-sdk-cli/sdks/project-uploads.md).

## Upload guides

* [Project files and folders](/api-sdk-cli/sdks/project-uploads.md) with the Python SDK.
* [CLI project uploads](/api-sdk-cli/clis/cli-projects-and-data-units.md) and [CLI Asset uploads](/api-sdk-cli/clis/cli-assets-and-folders.md).
* [Data Group automation](/api-sdk-cli/sdks/data-group-automation.md) using filename rules.
* [Annotation imports](/api-sdk-cli/sdks/annotation-imports.md), available through the Python SDK. Version 3.1.3 does not include an annotation-import CLI command.

## If something goes wrong

| Symptom                                 | Next step                                                                                                                                   |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| Authentication error                    | Confirm the API key and deployment URL in [Authentication and configuration](/api-sdk-cli/get-started/authentication-and-configuration.md). |
| A local upload fails                    | Inspect `batch.failed` and correct only the failed files.                                                                                   |
| Processing takes longer than 30 minutes | Keep the printed IDs and resume monitoring the existing Batch Queue.                                                                        |
| An image is missing or unreadable       | Inspect the Batch Queue results and Project Data before uploading it again.                                                                 |

***

> **Continue with Unitlab:** [AI training-data annotation](https://unitlab.ai/en/data-annotation)
