Python client for the Craaft API.
Project description
Craaft Python SDK
A small, synchronous Python client for the Craaft API. It wraps the REST endpoints with typed dataclasses, a sensible retry policy, and a friendly exception hierarchy.
Install
pip install craaft
Python 3.10 or newer.
Quickstart
from datetime import datetime, timedelta, timezone
from craaft import CraaftClient
# Reads CRAAFT_API_TOKEN (and optionally CRAAFT_BASE_URL) from the environment.
with CraaftClient() as client:
me = client.me.get()
print(f"Hi {me.name}")
project = client.projects.create(name="Demo", description="A new board")
card = client.projects.create_card(
project.id,
title="Ship the SDK",
column="todo",
position=1.0,
description="all the bits",
)
# Some fields (priority, due_date, size) are best set via PATCH after
# the card exists, since POST drops them on some server builds.
client.cards.update(
card.id,
priority="high",
due_date=datetime.now(timezone.utc) + timedelta(days=7),
)
client.cards.add_comment(card.id, body="lgtm")
# upcoming() and search() return CardSummary previews, not full cards.
for summary in client.cards.upcoming():
print(summary.title, summary.due_date, summary.project_name)
Examples
The examples/ directory has runnable scripts for the most common patterns. Each one is self-contained and cleans up after itself, so they're safe to run repeatedly:
| File | What it shows |
|---|---|
quickstart.py |
Sign in, create a card, leave a comment. |
card_lifecycle.py |
Create, set priority and due date via PATCH, comment, move between columns, delete. |
error_handling.py |
Which exceptions to catch and what fields they carry. |
retries.py |
Tuning RetryConfig and reacting to RateLimitError yourself. |
searching.py |
cards.search() and cards.upcoming(), both returning CardSummary. |
advanced_client.py |
Custom session, alternate base URL, user-agent, debug logging. |
Set CRAAFT_API_TOKEN (and optionally CRAAFT_BASE_URL) in your environment, then python examples/quickstart.py.
Configuration
from craaft import CraaftClient, RetryConfig
client = CraaftClient(
api_key="cra_...", # or CRAAFT_API_TOKEN env var
base_url="https://craaft.io/api/v1", # or CRAAFT_BASE_URL env var (default: prod)
timeout=30.0, # seconds, or (connect, read) tuple
retry=RetryConfig(max_attempts=5), # or retry=None to disable
user_agent="my-app/1.0",
)
Resources
| Sub-client | Methods |
|---|---|
client.me |
get(), update(name=, email=, username=) |
client.projects |
list(), get(id), create(name=, description=), update(id, ...), delete(id), list_cards(id), create_card(id, title=, column=, position=, ...), add_column(id, title=) |
client.cards |
update(id, ...), delete(id), upcoming(), search(q=, limit=20), list_comments(id), add_comment(id, body=) |
client.comments |
update(id, body=), delete(id) |
client.columns |
update(id, ...), delete(id) |
upcoming() and search() return list[CardSummary] - lightweight previews with project_name, column_key, and column_title. Every other read returns a full Card.
Models
Frozen dataclasses, keyword-only:
User- id, email, name, username, avatar_url, has_passwordProject- id, workspace_id, name, description, is_favorite, public_token, custom_css, background_image, color_scheme, text_color, total_cards, column_counts, columns, created_at, updated_atColumn- id, key, title, color, position, is_done, card_limitCard- id, project_id, column, title, position, description, due_date, assigned_user_id, size, priority, created_by, attachment_count, created_at, updated_atCardSummary- id, project_id, project_name, column_key, column_title, title, description, due_date, assigned_user_id, priority, updated_atComment- id, card_id, author_id, body, created_at, updated_at
due_date is a timezone-aware datetime. Naive datetimes you pass in are treated as UTC.
Errors
from craaft import CraaftAPIError, NotFoundError, RateLimitError
try:
client.projects.get("missing")
except NotFoundError:
...
except RateLimitError as e:
sleep(e.retry_after or 1)
except CraaftAPIError as e:
print(e.status_code, e.message, e.request_id)
Hierarchy: CraaftError is the root. API failures raise CraaftAPIError or one of its subclasses (AuthenticationError, PermissionError, NotFoundError, ConflictError, PlanLimitError, ValidationError, RateLimitError, ServerError). Network failures raise CraaftConnectionError or CraaftTimeoutError.
Retries
The client retries 429, 502, 503, 504, and network errors with exponential backoff and Retry-After-aware pauses. Writes (POST / PATCH / DELETE) skip 5xx retries by default, since the server may have applied the change before responding. Set RetryConfig(retry_writes_on_5xx=True) if your workload is safe to retry.
Logging
The client logs one DEBUG line per HTTP attempt (method, path, status, duration, attempt number) on the craaft logger. The auth header is never logged.
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("craaft").setLevel(logging.DEBUG)
Development
pip install -e ".[dev]"
pytest
ruff check
mypy
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file craaft-1.0.0.tar.gz.
File metadata
- Download URL: craaft-1.0.0.tar.gz
- Upload date:
- Size: 21.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
741b7d072f292ce203068a432b8941af61018ba3e5a1802321419ab6caa2d002
|
|
| MD5 |
1c7d421ad364e450b005afa0559f9766
|
|
| BLAKE2b-256 |
f09d3a6fc96df244e24b2a5c326003cac9a9bbafcc09745ef509354c32d9f207
|
File details
Details for the file craaft-1.0.0-py3-none-any.whl.
File metadata
- Download URL: craaft-1.0.0-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd3212d6831a7a45fee6fd526b03b553f39fb2a2ac5c797e82872c65e57c96ed
|
|
| MD5 |
25257acc59525bb64ecf510ce35c3a8e
|
|
| BLAKE2b-256 |
0cee6563dff6b009c7256b2e081ca632a469a0623ffe50d3b188db54ffe30703
|