CloudFactory AI Platform Python Client
Official Python SDK for the CloudFactory AI Platform. Download COCO format annotations from your projects with flexible filtering (batches, work items, timestamps), concurrent workers, automatic retries, and progress tracking.
Prerequisites
Before you start, you will need:
- Python 3.10 or later
- A CloudFactory API Key
- Your Project ID
- Your Space ID
Installation
uv add cf-ai-platform-client
Or with pip:
pip install cf-ai-platform-client
Quick Start
Option A: Synchronous (simpler, no async required)
If you are writing a script, running in a Jupyter notebook, or are not familiar with Python async/await syntax, use SyncCFUserClient:
from cf_ai_platform_client import SyncCFUserClient
with SyncCFUserClient.create_with_api_key("YOUR_API_KEY") as client:
summary = client.download_project(
project_id="YOUR_PROJECT_ID",
space_id="YOUR_SPACE_ID",
destination="./downloads"
)
print(f"Downloaded {summary.successful} of {summary.total_items} items")
if summary.failed > 0:
print(f" {summary.failed} items failed")
Option B: Async script or entry point
If you are writing an async application or prefer async/await syntax, use CFUserClient:
import asyncio
from cf_ai_platform_client import CFUserClient
async def main():
async with CFUserClient.create_with_api_key("YOUR_API_KEY") as client:
summary = await client.download_project(
project_id="YOUR_PROJECT_ID",
space_id="YOUR_SPACE_ID",
destination="./downloads"
)
print(f"Downloaded {summary.successful} of {summary.total_items} items")
asyncio.run(main())
Usage Examples
The examples below use SyncCFUserClient for simplicity. Async equivalents use CFUserClient with await and async with.
Basic Download
Download all COCO annotations from a project:
from cf_ai_platform_client import SyncCFUserClient
with SyncCFUserClient.create_with_api_key("MY_API_KEY") as client:
summary = client.download_project(
project_id="proj_abc123",
space_id="space_456",
destination="./my_downloads"
)
if summary.failed > 0:
print("Some downloads failed:")
for result in summary.results:
if not result.success:
print(f" - Item {result.item_id}: {result.error}")
Filter by Batch IDs
Download only specific batches (up to 100 batch IDs):
from cf_ai_platform_client import SyncCFUserClient
with SyncCFUserClient.create_with_api_key("MY_API_KEY") as client:
summary = client.download_project(
project_id="proj_abc123",
space_id="space_456",
destination="./my_downloads",
batch_ids=[1, 2, 3]
)
Filter by Work Item IDs
Download specific work items by their UUIDs (up to 100):
from cf_ai_platform_client import SyncCFUserClient
with SyncCFUserClient.create_with_api_key("MY_API_KEY") as client:
summary = client.download_project(
project_id="proj_abc123",
space_id="space_456",
destination="./my_downloads",
work_item_ids=[
"550e8400-e29b-41d4-a716-446655440000",
"6ba7b810-9dad-11d1-80b4-00c04fd430c8"
]
)
Filter by Date (ISO 8601)
Filter by creation date:
from cf_ai_platform_client import SyncCFUserClient
with SyncCFUserClient.create_with_api_key("MY_API_KEY") as client:
summary = client.download_project(
project_id="proj_abc123",
space_id="space_456",
destination="./my_downloads",
created_at_from="2026-01-01T00:00:00Z",
created_at_to="2026-01-31T23:59:59Z"
)
Filter by last updated date:
from cf_ai_platform_client import SyncCFUserClient
with SyncCFUserClient.create_with_api_key("MY_API_KEY") as client:
summary = client.download_project(
project_id="proj_abc123",
space_id="space_456",
destination="./my_downloads",
updated_at_from="2026-02-11T00:00:00Z",
updated_at_to="2026-02-18T23:59:59Z"
)
Note: these filters apply to work items — when they were created and last updated.
Combine Multiple Filters
All filters can be combined freely:
from cf_ai_platform_client import SyncCFUserClient
with SyncCFUserClient.create_with_api_key("MY_API_KEY") as client:
summary = client.download_project(
project_id="proj_abc123",
space_id="space_456",
destination="./my_downloads",
batch_ids=[1, 2],
created_at_from="2026-01-01T00:00:00Z",
created_at_to="2026-01-31T23:59:59Z",
max_workers=15
)
Configure Concurrency
By default the SDK downloads 10 work items concurrently. Increase this for faster downloads or decrease it to reduce load:
from cf_ai_platform_client import SyncCFUserClient
with SyncCFUserClient.create_with_api_key("MY_API_KEY") as client:
summary = client.download_project(
project_id="proj_abc123",
space_id="space_456",
destination="./my_downloads",
max_workers=20 # default: 10
)
Inspect Download Results
Access detailed information about each downloaded item:
from cf_ai_platform_client import SyncCFUserClient
with SyncCFUserClient.create_with_api_key("MY_API_KEY") as client:
summary = client.download_project(
project_id="proj_abc123",
space_id="space_456",
destination="./my_downloads"
)
for result in summary.results:
if result.success:
print(f"✅ {result.item_id} -> {result.file_path}")
else:
print(f"❌ {result.item_id}: {result.error}")
Custom Base URL
Use a custom API endpoint (e.g., for staging):
from cf_ai_platform_client import SyncCFUserClient
with SyncCFUserClient.create_with_api_key(
api_key="MY_API_KEY",
base_url="https://api.staging.ai.cloudfactory.app/api/v1"
) as client:
summary = client.download_project(
project_id="proj_abc123",
space_id="space_456",
destination="./my_downloads"
)
File Organization
Downloaded COCO annotation files are organized by batch name:
destination/
├── Default/
│ ├── <work_item_id>.json
│ └── <work_item_id>.json
└── Training_Batch_001/
└── <work_item_id>.json
- Files are grouped by batch name (fetched from batch metadata)
- If no batches have been defined, all items will be under the
Defaultbatch - File naming:
{work_item_id}.{extension} - Extension is auto-detected from URL (defaults to
.json) - Each
.jsonfile is a COCO-format annotation with anasset_urlfield injected into theinfoblock so you can trace it back to the original asset - Only COMPLETED work items are downloaded by default
API Reference
SyncCFUserClient (synchronous)
Synchronous wrapper around CFUserClient. Runs a background event loop in a daemon thread — all methods block until complete. Use with for context management.
Methods
create_with_api_key(api_key: str, base_url: Optional[str] = None) -> SyncCFUserClient
Create a client instance with API key authentication.
Parameters:
api_key(str): Your CloudFactory API keybase_url(Optional[str]): Custom API base URL (default: production)
Returns: Configured SyncCFUserClient instance
download_project(project_id, space_id, destination, ...) -> DownloadSummary
Download all COCO annotations from a project with flexible filtering options. Blocks until complete.
All parameters are identical to CFUserClient.download_project.
close() -> None
Close HTTP clients and stop the background event loop. Called automatically when using with.
CFUserClient (async)
Async client for the CloudFactory AI Platform. All methods must be awaited; use async with for context management.
Architecture
The download process follows these steps:
- Fetch Batches: Retrieve batch metadata (ID → name mapping) from the Platform API
- Fetch Manifest: Query work items with optional filters (status defaults to "COMPLETED")
- Parallel Downloads: Use asyncio with semaphore to download annotations concurrently
- For Each Item:
- Fetch annotation metadata from Platform API
- Extract COCO results URL from annotation metadata
- Generate signed download URL from Space API
- Download file content with retry logic
- Save to disk organized by batch name
- Return Summary: Aggregate statistics and per-item results
Methods
create_with_api_key(api_key: str, base_url: Optional[str] = None) -> CFUserClient
Create a client instance with API key authentication.
Parameters:
api_key(str): Your CloudFactory API keybase_url(Optional[str]): Custom API base URL (default: production)
Returns: Configured CFUserClient instance
async download_project(project_id, space_id, destination, ...) -> DownloadSummary
Download all COCO annotations from a project with flexible filtering options. Must be awaited.
Parameters:
project_id(str): The project ID to downloadspace_id(str): The space ID (required for generating signed URLs)destination(str): Local directory path to save filesbatch_ids(Optional[list[int]]): Filter by specific batch IDs (max 100). Downloads all if Nonework_item_ids(Optional[list[str]]): Filter by specific work item IDs (UUID format). Downloads all if Nonecreated_at_from(Optional[str]): Filter items created on or after this timestamp (ISO 8601 format, e.g., "2026-01-15T10:30:00Z")created_at_to(Optional[str]): Filter items created on or before this timestamp (ISO 8601 format)updated_at_from(Optional[str]): Filter items updated on or after this timestamp (ISO 8601 format)updated_at_to(Optional[str]): Filter items updated on or before this timestamp (ISO 8601 format)max_workers(int): Maximum concurrent downloads (default: 10)limit(Optional[int]): Items per page when fetching the manifest (1–100, default: API default of 20)
Returns: DownloadSummary with statistics and detailed results
Raises:
httpx.HTTPStatusError: If API requests failOSError: If file system operations fail
async close() -> None
Close HTTP clients and cleanup resources. Must be awaited. Called automatically when using async with.
Models
DownloadSummary
Summary statistics for a download operation.
| Field | Type | Description |
|---|---|---|
total_items |
int |
Total number of work items processed |
successful |
int |
Number of files successfully downloaded |
failed |
int |
Number of files that could not be downloaded |
results |
list[DownloadResult] |
Per-item details |
DownloadResult
Result of a single work item download.
| Field | Type | Description |
|---|---|---|
item_id |
str |
ID of the work item |
batch_id |
Optional[int] |
Batch ID the item belongs to |
success |
bool |
Whether the download succeeded |
file_path |
Optional[str] |
Path where file was saved (if successful) |
error |
Optional[str] |
Error message (if failed) |
Error Handling
The SDK includes comprehensive error handling:
| Error | Likely Cause |
|---|---|
ValueError |
API key cannot be empty |
| HTTP 401 | API key is invalid or expired |
| HTTP 404 | Project ID or Space ID does not exist |
OSError |
Destination directory permissions issue |
Automatic Retries
Downloads automatically retry up to 3 times with exponential backoff (2-10 seconds) for:
- Network errors and timeouts (
httpx.HTTPError,httpx.TimeoutException) - All HTTP errors (including 4xx and 5xx status codes)
Retries apply only to the download phase (fetching files from signed URLs). API calls to fetch manifests, batches, and annotations do not have automatic retries.
Graceful Failures
If a download fails after retries:
- Error is logged
- Item is marked as failed in results
- Download continues for remaining items
- Summary includes failure details
Example Error Handling
import logging
from cf_ai_platform_client import SyncCFUserClient
logging.basicConfig(level=logging.INFO)
with SyncCFUserClient.create_with_api_key("MY_API_KEY") as client:
try:
summary = client.download_project(
project_id="proj_abc123",
space_id="space_456",
destination="./downloads"
)
if summary.failed > 0:
print(f"\n⚠️ {summary.failed} items failed to download:")
for result in summary.results:
if not result.success:
print(f" - {result.item_id}: {result.error}")
except Exception as e:
print(f"❌ Download failed: {e}")
raise
Requirements
- Python 3.10 to 3.14 (actively supported versions)
- Dependencies:
httpx >= 0.27.0- HTTP clientpydantic >= 2.6.0- Data validationtqdm >= 4.66.0- Progress barstenacity >= 8.2.0- Retry logic
Development
Setup
This project uses uv for fast dependency management. The setup script installs uv with checksum verification for security:
# Clone the repository
git clone https://github.com/cloudfactory/cf-ai-platform-client-python.git
cd cf-ai-platform-client-python
# Run setup (installs uv with checksum verification)
./setup.sh --dev
Alternative uv installation methods:
If you prefer to install uv yourself:
# macOS (recommended)
brew install uv
# Using pipx
pipx install uv
# Using pip
pip install uv
# Then install dependencies
uv sync --all-extras
Security note: The setup script downloads a pinned uv release (v0.10.4) with SHA256 checksum verification to prevent supply-chain attacks. CI/CD workflows use the official astral-sh/setup-uv@v4 GitHub Action.
Running Tests
# Run all tests with coverage
uv run pytest
# Run with verbose output
uv run pytest -v
# Run specific test file
uv run pytest tests/test_client.py
# Generate HTML coverage report
uv run pytest --cov=src --cov-report=html
Code Quality
# Format code
uv run ruff format src tests
# Lint code
uv run ruff check src tests
# Type checking
uv run mypy src
# Run all checks
uv run ruff format src tests && uv run ruff check --fix src tests && uv run mypy src
Building and Publishing
# Build distribution packages
uv build
# Publish to TestPyPI (for testing)
uv publish --publish-url https://test.pypi.org/legacy/
# Publish to PyPI (production)
uv publish
Note: Publishing is automated via GitHub Actions. Push to main triggers the production release workflow.
License
MIT License - see LICENSE file for details.
Metadata
Release files for cf-ai-platform-client 0.3.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 | Provenance | Actions |
|---|---|---|---|---|
| cf_ai_platform_client-0.3.0.tar.gz | 89.1 kB | With provenance | Details for cf_ai_platform_client-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cf_ai_platform_client-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for cf_ai_platform_client-0.3.0-py3-none-any.whl |
Total release size: 110.3 kB
Release files / cf_ai_platform_client-0.3.0.tar.gz
| Download URL | cf_ai_platform_client-0.3.0.tar.gz |
|---|---|
| Size | 89.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
56c57b47167e74403a3eafeccb7b6636ea528ee4088c13060839720713ba57d1
|
|
BLAKE2b-256 checksum How to use checksums |
0a532f6a6f60371568048d763985208069d32cad0a48cf320076aa3d2027292b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / cf_ai_platform_client-0.3.0-py3-none-any.whl
| Download URL | cf_ai_platform_client-0.3.0-py3-none-any.whl |
|---|---|
| Size | 21.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7a4a3150e26b0399f8d5e6884217c257ada8b265561191df3ab965a8f06b0a35
|
|
BLAKE2b-256 checksum How to use checksums |
fed41586afc2e6ea255e9ecc8b4e5b73c2379ea437d9172341c4d1ead2323cb3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logSecurity for cf-ai-platform-client 0.3.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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for cf_ai_platform_client-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logA 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.