Skip to content

capawesome-team/cloud-python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

capawesome-cloud

PyPI version PyPI downloads license

Python SDK for the Capawesome Cloud API.

It provides a fully typed, synchronous interface for managing apps, live update channels and deployments, native builds, app store destinations, and more.

Note: The Capawesome Cloud API is still in development and may change without notice. Response types intentionally expose only the most relevant properties to minimize breaking changes.

SDKs

Official SDKs for the Capawesome Cloud API:

Language Package Repository
Node.js @capawesome/cloud-sdk cloud-node
Python capawesome-cloud cloud-python

Installation

pip install capawesome-cloud

Requirements: Python 3.9 or later.

Getting started

Create an API token in the Capawesome Cloud Console and pass it to the client (or set the CAPAWESOME_CLOUD_TOKEN environment variable, with CAPAWESOME_TOKEN accepted as a fallback):

from capawesome_cloud import CapawesomeCloud

client = CapawesomeCloud(token="cap_...")

for app in client.apps.list():
    print(app.id, app.name)

The client holds a connection pool, so reuse a single instance. Use it as a context manager (or call client.close()) to release connections when done:

with CapawesomeCloud(token="cap_...") as client:
    ...

Configuration

Option Type Default Description
token str CAPAWESOME_CLOUD_TOKEN env var API token used to authenticate.
base_url str https://api.cloud.capawesome.io Base URL of the API (for self-hosting/testing).
timeout float 30.0 Request timeout in seconds.
max_retries int 2 Retries with exponential backoff. 429 is retried for any request; network/5xx failures are retried only for idempotent methods (GET/PUT/DELETE), never POST/PATCH.
backoff_factor float 0.5 Base delay for the retry backoff.
http_client httpx.Client None Bring your own pre-configured httpx.Client.

Usage

Resources mirror the API's path hierarchy. App-scoped resources are nested under client.apps.*; organization-scoped resources are on the client directly (e.g. client.jobs). Every app-scoped method takes app_id as its first argument.

Apps

apps = client.apps.list()
app = client.apps.get(app_id)
created = client.apps.create(name="My App", type="capacitor")
client.apps.update(app_id, name="Renamed App")
client.apps.delete(app_id)

Live updates

# Create a channel
channel = client.apps.channels.create(app_id, name="production")

# Pause / resume a channel
client.apps.channels.pause(app_id, channel.id)
client.apps.channels.resume(app_id, channel.id)

Deployments

Promote a build to a channel (live updates) or a destination (app store publishing):

deployment = client.apps.deployments.create(
    app_id,
    app_build_id=app_build_id,
    app_channel_name="production",
    rollout_percentage=0.5,
)

Native builds

build = client.apps.builds.create(app_id, platform="ios", git_ref="main")

# Poll the job that processes the build until it finishes
job = client.jobs.wait(build.job_id)
print(job.status)

logs = client.jobs.logs(job.id)

Build artifacts

Binary downloads return bytes:

data = client.apps.builds.artifacts.download(app_id, build_id, artifact_id)
with open("artifact.ipa", "wb") as file:
    file.write(data)

You can also obtain a signed, time-limited download URL:

result = client.apps.builds.artifacts.get_download_url(app_id, build_id, artifact_id)
print(result["url"])

Certificates

file may be a path, raw bytes, or an open binary file object:

import os

certificate = client.apps.certificates.create(
    app_id,
    name="Distribution Certificate",
    platform="ios",
    type="production",
    file="distribution.p12",
    password=os.environ["CERT_PASSWORD"],
)

Environments, secrets & variables

environment = client.apps.environments.create(app_id, name="production")

client.apps.environments.secrets.create(
    app_id,
    environment.id,
    key="API_KEY",
    value=os.environ["API_KEY"],
)

client.apps.environments.variables.create(
    app_id,
    environment.id,
    key="API_URL",
    value="https://api.example.com",
)

Pagination

List methods return an iterator that lazily pages through all results:

for device in client.apps.devices.list(app_id):
    print(device.id, device.app_version_name)

# Collect everything into a list
channels = client.apps.channels.list(app_id).to_list()

To fetch a single page (for manual offset control), use list_page():

page = client.apps.channels.list_page(app_id, limit=20, offset=0)

Responses

Responses are typed Pydantic models. App-scoped models are prefixed with App (AppChannel, AppWebhook, AppBuild, ...) to match the API's entity names. Only the most relevant fields are declared; any additional fields the API returns are still accessible (e.g. via model_dump()) but are not part of the public contract and should not be relied upon.

channel = client.apps.channels.get(app_id, channel_id)
print(channel.name, channel.created_at)   # documented fields
print(channel.model_dump())               # full raw payload, incl. extra fields

Clearing fields

Update methods only send the arguments you pass. To clear a nullable field, pass None; omit the argument to leave it unchanged.

# Pin a device to a channel
client.apps.devices.update(app_id, device_id, forced_app_channel_id="ch_123")

# Unpin it again (sends null)
client.apps.devices.update(app_id, device_id, forced_app_channel_id=None)

Available resources

Resource Description
client.apps Create, read, update, delete and transfer apps.
client.apps.channels Manage live update channels (incl. pause/resume).
client.apps.deployments Promote builds to channels or destinations.
client.apps.builds Trigger and manage native builds.
client.apps.builds.artifacts List and download build artifacts.
client.apps.build_sources Register and download native build sources.
client.apps.certificates Manage signing certificates.
client.apps.destinations Manage app store publishing destinations.
client.apps.environments Manage environments, secrets and variables.
client.apps.automations Manage build automations.
client.apps.devices Manage registered devices.
client.apps.webhooks Manage app webhooks.
client.jobs Inspect background jobs and their logs.

Error handling

Any non-2xx response is raised as a CapawesomeCloudError, carrying the HTTP status, the message from the API, and the raw body:

from capawesome_cloud import CapawesomeCloud, CapawesomeCloudError

client = CapawesomeCloud(token="cap_...")

try:
    client.apps.get("unknown")
except CapawesomeCloudError as error:
    print(error.status)       # 404
    print(error.status_text)  # "Not Found"
    print(error.message)      # "App not found."
    print(error.body)         # {"message": "App not found."}

Network failures raise APIConnectionError / APITimeoutError, which also derive from CapawesomeCloudError — so a single except CapawesomeCloudError catches every error the SDK can raise. For those, status is None.

Development

Setup

Clone the repository, then create a virtual environment and install the package with its development dependencies:

python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

Commit messages follow Conventional Commits, enforced by Commitizen — run cz commit for a guided prompt. Common commands during development:

Command Description
python -m build Build the package into dist/.
ruff check src tests examples Run the linter.
ruff format src tests examples Auto-format the code.
ruff format --check src tests examples Check formatting without writing.
mypy Type-check the package.
cz commit Create a Conventional Commit.

Testing

Tests are written with pytest and live in the tests/ directory. HTTP is mocked with RESPX, so the suite makes no network calls:

pytest                          # run the suite once
pytest --cov=capawesome_cloud   # run with a coverage report

Publishing

Releases are driven by Commitizen, which derives the next version and changelog entries from Conventional Commits.

  1. Make sure main is up to date and CI is green.
  2. Run cz bump. This bumps the version (in [tool.commitizen] and src/capawesome_cloud/_version.py), regenerates CHANGELOG.md, and creates a release commit plus a matching vX.Y.Z tag — all locally, nothing is pushed yet. Pass --dry-run first if you want to preview the result.
  3. Review the generated commit and changelog, then push everything: git push --follow-tags origin main.
  4. Build the distributions with python -m build, then publish to PyPI with python -m twine upload dist/* (requires pip install build twine).

License

See LICENSE.

About

⚙️ Python library for the Capawesome Cloud API.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages