Skip to content

pyclann

Python client library for the Clann family-tree API.

Installation

pip install pyclann

Requires Python 3.10+.

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 share a hostname

Call client.login(email, password) before any other method. Tokens expire according to the server 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

All exceptions inherit from ClannError:

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:

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"), as the server uses it verbatim in URL paths.