Python SDK¶
Programmatic access to HomeCloud from Python 3.
Package: homecloud-sdk · Import: from homecloud import HomeCloud
Install¶
If the package is not on PyPI in your environment yet:
pip install "git+https://github.com/HomeCloudLab/homecloud-sdk.git"
# or editable checkout:
pip install -e ../homecloud-sdk
Create a client¶
from homecloud import HomeCloud
# Explicit (recommended for servers)
client = HomeCloud(
access_key="HCAK...",
secret_key="...",
)
# Environment: HC_ACCESS_KEY_ID / HC_SECRET_ACCESS_KEY / HC_APEX
client = HomeCloud.from_env()
# Profile file ~/.homecloud/credentials
client = HomeCloud()
client = HomeCloud(profile="ci")
Async¶
from homecloud import AsyncHomeCloud
async with AsyncHomeCloud.from_env() as client:
await client.so.upload("docs", "./a.txt", key="a.txt")
await client.mq.send("orders", {"id": 1})
from homecloud_sdk import … still works for compatibility; prefer from homecloud import ….
Object Storage¶
client.so.upload("docs", "./readme.md", key="readme.md")
client.so.upload(
"media",
body=video_bytes,
key="videos/clip.mp4",
content_type="video/mp4",
)
meta = client.so.head_object("docs", "readme.md")
client.so.download("docs", "readme.md", "./copy.md")
print(client.so.get_object_uri("docs", "readme.md"))
print(client.so.generate_presigned_url("docs", "readme.md", expires_in=3600))
client.so.list_objects("docs", prefix="readme")
# All pages under a prefix (continuation tokens)
keys = client.so.list_all_objects("docs", prefix="photos/", recursive=True)
client.so.copy("dest-bucket", "a.txt", "folder/a.txt", source_bucket="src-bucket")
client.so.move("dest-bucket", "a.txt", "folder/a.txt", source_bucket="src-bucket")
client.so.delete("docs", "readme.md")
# One API: local↔bucket or bucket↔bucket (same shape as CLI `so sync`)
client.so.sync("./dist", "so://my-website/", delete=True)
client.so.sync("so://docs/", "./site")
client.so.sync("so://photos/", "so://backup/photos/", delete=True)
Management helpers (list_buckets, create_bucket) support Access Key (SigV1) using the user’s effective policies (including system groups). homecloud login is mainly for interactive console sessions or special cases (e.g. IR ↔ Docker), not for listing buckets when credentials are present.
Message Queues¶
client.mq.send("orders", {"id": 1})
client.mq.send("orders", [{"id": 1}, {"id": 2}]) # batch 1–10
messages = client.mq.receive("orders", max_messages=10, wait_seconds=5)
for msg in messages:
process(msg)
client.mq.delete("orders", msg["sequence"])
client.mq.receive("orders", max_messages=10, delete=True) # receive + ack
client.mq.purge("orders")
dlq = client.mq.receive_dlq("orders", max_messages=5)
client.mq.delete_dlq("orders", 7)
client.mq.purge_dlq("orders")
Functions¶
for fn in client.functions.list():
print(fn["name"], fn.get("status"))
result = client.functions.invoke("hello", {"name": "Ada"})
print(result)
print(client.functions.url("hello"))
client.functions.enable_url("hello")
client.functions.disable_url("hello")
for row in client.functions.logs("hello")["items"]:
print(row)
# Breaking (0.5.14+): logs() returns {"items", "next_cursor"} — not a bare list.
detail = client.functions.get_invocation("hello", invocation_id)
for event in client.functions.stream_logs("hello", invocation_id, timeout_seconds=120):
if event.get("type") == "log":
print(event.get("line"))
elif event.get("type") in {"end", "done"}:
break
Domains (0.5.15+)¶
hosts = client.domains.list_hosts(domain_id)
client.domains.update_record(domain_id, record_id, record_type="A", record="1.2.3.5", host="www")
client.domains.detach(attachment_id)
Tasks and Diagrams¶
Management plane — user JWT (login) or user-bound Access Key SigV1 (not a bare service-account key).
# Smart search (same q grammar as the console)
items = client.tasks.search("cert @alice &ops due:overdue")
detail = client.tasks.get("TASK-12")
# Create / assign by username
client.tasks.create(
"Rotate cert",
type="change",
priority="p2",
assignees=["alice"],
label_names=["ops"],
)
client.tasks.assign_me("TASK-12", status="in_progress")
client.tasks.comment("TASK-12", "Deployed to staging")
for event in client.tasks.activity("TASK-12"):
print(event["event_type"], event.get("payload"))
client.tasks.archive("TASK-12", cancel=True)
diagrams = client.diagrams.list()
doc = client.diagrams.get(diagram_id)
client.diagrams.create("Production plan", description="Draft")
client.diagrams.update(diagram_id, name="Prod", document=doc["document"], revision=doc["revision"])
Mail¶
boxes = client.mail.list_mailboxes()
msgs = client.mail.list_messages(mailbox_id=boxes[0]["id"], limit=20)
detail = client.mail.get_message(msgs[0]["id"])
raw = client.mail.download_attachment(msgs[0]["id"], "0")
Image Registry¶
Secrets¶
print(client.secrets.list()) # console JWT — metadata
client.secrets.create("my-secret", API_KEY="test") # create + seed (Access Key)
print(client.secrets.get_value("my-secret"))
print(client.secrets.get_value("my-secret", "API_KEY", "DB_HOST"))
print(client.secrets.get_value("my-secret", format="env")) # API_KEY=x (no trailing \\n)
client.secrets.put_value("my-secret", {"API_KEY": "rotated"})
client.secrets.put_value("my-secret", API_KEY="test", merge=True)
client.secrets.put_value("my-secret", "API_KEY=x", format="env", merge=True)
Flat map codecs (JSON/ENV/YAML) for files/CLI: homecloud_sdk.secret_formats.
Errors¶
from homecloud import HomeCloud, NotFoundError, HomeCloudError
try:
HomeCloud.from_env().so.head_object("docs", "missing.txt")
except NotFoundError as exc:
print(exc.resource_type, exc.resource)
except HomeCloudError as exc:
print(exc.status_code, exc)
| Type | Typical status |
|---|---|
NotFoundError |
404 |
UnauthorizedError |
401 |
PermissionDeniedError |
403 |
BadRequestError |
400 |
ConflictError |
409 |
RateLimitError |
429 |
ServiceUnavailableError |
502–504 |
ApiError |
other HTTP errors |
Environment variables¶
| Variable | Short | Effect |
|---|---|---|
HOMECLOUD_PROFILE |
HC_PROFILE |
Active profile |
HOMECLOUD_ACCESS_KEY_ID |
HC_ACCESS_KEY_ID |
Access key |
HOMECLOUD_SECRET_ACCESS_KEY |
HC_SECRET_ACCESS_KEY |
Secret |
HOMECLOUD_ACCOUNT_ID |
HC_ACCOUNT_ID |
Optional account |
HOMECLOUD_APEX |
HC_APEX |
Platform domain |
Credentials file: ~/.homecloud/credentials (JSON multi-profile).
Relation to the CLI¶
homecloud-cli is a Typer/Rich wrapper around this SDK. Prefer the CLI for shell/CI sync commands and the SDK inside application code.