Python client library for the Clann family-tree API
Project description
pyclann
Python client library for the Clann family-tree API.
Installation
pip install pyclann
Quick start
from pyclann import ClannClient
client = ClannClient(
api_url="http://localhost:8090",
auth_url="http://localhost:8081", # ullav-user-management service
)
client.login(email="user@example.com", password="secret")
# Family trees
trees = client.trees.list(owner="alice")
tree = client.trees.create("walsh-family", "Walsh Family", owner="alice")
# Persons
father = client.persons.create(
"Walsh", "Patrick", "Male",
trees=["walsh-family"],
date_of_birth="1820-06-01",
created_by="alice",
)
son = client.persons.create(
"Walsh", "Michael", "Male",
trees=["walsh-family"],
created_by="alice",
)
# Relationships
client.relationships.add(son.id, "Father", father.id)
rels = client.relationships.get(son.id) # RelationshipsResponse
# Life events
client.life_events.create(
father.id, "Born in Galway", "Birth",
date="1820-06-01",
created_by="alice",
)
# Research notes
note = client.notes.create(
"Walsh Family Research",
trees=["walsh-family"],
body="Found records at Galway archives.",
is_shared=True,
created_by="alice",
)
client.notes.create_reply(note.id, "Also check Dublin records.", created_by="alice")
# Profile picture
with open("patrick.jpg", "rb") as f:
client.persons.upload_image(father.id, f.read(), "image/jpeg")
image_bytes = client.persons.get_image(father.id) # public endpoint, no auth needed
Authentication
ClannClient authenticates against the ullav-user-management service, which issues
the JWT accepted by the Clann server.
api_url— Clann server base URL (e.g.http://clann-server:8090)auth_url— auth service base URL (e.g.http://ullav-user-management:8081); omit if both services are behind the same proxy
Call client.login(email, password) before any other method. Tokens expire according
to the server's configuration; call login() again to refresh.
Resource clients
| Attribute | Resource |
|---|---|
client.trees |
Family tree CRUD, primary flag, team assignment, avatar image |
client.persons |
Person CRUD, tree membership, profile/life-story media |
client.relationships |
Add/remove father/mother/sibling/spouse edges, family-tree view |
client.life_events |
Life event CRUD per person |
client.notes |
Research note CRUD, folder assignment, replies |
client.folders |
Research folder CRUD |
client.chat |
AI chat session and message management |
client.ai_settings |
Per-user AI provider settings (encrypted BYOK) |
Error handling
from pyclann import ClannAuthError, ClannNotFoundError, ClannValidationError
try:
tree = client.trees.get("non-existent-tree")
except ClannNotFoundError:
print("tree not found")
except ClannAuthError:
client.login(email, password) # token expired — re-authenticate
except ClannValidationError as e:
print("bad request:", e)
| Exception | HTTP status |
|---|---|
ClannAuthError |
401 / 403, or login() not called |
ClannNotFoundError |
404 |
ClannValidationError |
400 |
ClannServerError |
5xx |
ClannError |
base class |
Record IDs
The Clann API uses SurrealDB record IDs of the form "table:ulid", e.g.
"person:01jd4a8xyz". All client methods that take an *_id parameter accept
either the full form or the bare ULID — the library strips the table prefix when
building URL paths.
person = client.persons.get("person:01jd4a8xyz") # full ID
person = client.persons.get("01jd4a8xyz") # bare ULID — both work
Note: when specifying a related_id in relationship calls, always pass the full
record ID ("person:01jd4a8xyz"), since the server uses it verbatim in URL paths.
Relationship types
from pyclann import RelationshipType, SiblingType
# Add a father
client.relationships.add(child.id, RelationshipType.FATHER, father.id)
# Add a sibling — sibling_type is required
client.relationships.add(
person.id,
RelationshipType.SIBLING,
sibling.id,
sibling_type=SiblingType.BROTHER,
)
# Add a spouse with dates
client.relationships.add(
person.id,
RelationshipType.SPOUSE,
spouse.id,
spouse_from="1845-09-14",
)
# Remove a relationship
client.relationships.remove(child.id, RelationshipType.FATHER, father.id)
Image uploads
Profile pictures accept JPEG or PNG only (max 2 MB). Life-story media accepts the same image formats on Individual/Family plans; Professional/Enterprise plans also allow video (MP4, MOV, WebM), audio (MP3, WAV, OGG), and PDF.
# Upload
with open("profile.jpg", "rb") as f:
client.persons.upload_image(person.id, f.read(), "image/jpeg")
# Download — no login() required
data = client.persons.get_image(person.id)
with open("downloaded.jpg", "wb") as f:
f.write(data)
Licence
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 pyclann-0.1.0.tar.gz.
File metadata
- Download URL: pyclann-0.1.0.tar.gz
- Upload date:
- Size: 25.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7a52f0d0529ff49b871805c9961363fa3a34b3d7227e8056714a4248402a0c2a
|
|
| MD5 |
e1d603cdb07be5b82b152e904cb5fdee
|
|
| BLAKE2b-256 |
fea6bd5b6054f1bac9d61dd4bffc729820fc3cbe715d8d2d9aa57a30452a45ce
|
File details
Details for the file pyclann-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pyclann-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3775b63c596487d5ddd87bc7eb0112d96bbf3f12701c2d7c905d2fdfad280b0b
|
|
| MD5 |
aaf9a46c475f36761f80539ecbff631a
|
|
| BLAKE2b-256 |
b883c4be48010dfa12ba1ff98498d47c4d0fec48585bdf2937e770b4e5ef93c0
|