Skip to main content

weltenfw — v0.4.1

WeltenHub Client Framework — typed REST client, Pydantic v2 schemas, and a pluggable storage-backend pattern for the WeltenHub Story Universe API.

CI PyPI Python License: MIT

Installation

pip install iil-weltenfw                  # core (httpx + pydantic)
pip install iil-weltenfw[django]          # + Django AppConfig + DjangoCache

Quick Start — Low-Level Client

from weltenfw import WeltenClient

with WeltenClient(
    base_url="https://weltenforger.com/api/v1",
    token="your-token",
) as client:
    world = client.worlds.create(WorldCreateInput(
        name="Aldoria", setting_era="medieval",
    ))
    chars = client.characters.list(world=str(world.id))
    locs  = client.locations.list(world=str(world.id))
    stories = client.stories.list(world=str(world.id))
    scenes  = client.scenes.list(story=str(stories.results[0].id))

Async

async with WeltenClient(base_url=..., token=...) as client:
    world = await client.worlds.aget(world_id)
    locs  = await client.locations.alist(world=world_id)

Django Integration

# settings.py
INSTALLED_APPS  = [..., "weltenfw.django"]
WELTENHUB_URL   = "https://weltenforger.com/api/v1"
WELTENHUB_TOKEN = env("WELTENHUB_TOKEN")

# services.py
from weltenfw.django import get_client
client = get_client()   # lazy singleton, one per worker

Storage Backend Pattern (ADR-117)

weltenfw ships WeltenhubBackend — a higher-level write/read facade on top of WeltenClient. Consumer apps (bfagent, travel-beat, …) use this to keep Weltenhub as the single source of truth without duplicating data.

Two Scenarios — same API

from weltenfw.backends import WeltenhubBackend

backend = WeltenhubBackend(
    base_url="https://weltenforger.com/api/v1",
    token=token,   # user token (A) or service token (B)
)

Scenario A — user has Weltenhub account: token = user.weltenhub_token → data visible in Weltenhub UI immediately.

Scenario B — user not yet linked: token = WELTENHUB_API_KEY (service token) → data stored, UUID returned, UI locked until user links their account. No duplication; consumer stores only UUID.


Backend API Reference

Worlds

Method Signature Returns
create_world (name, description, setting_era, **kw) WorldResult
get_world (world_id) WorldResult
list_worlds (search, page) WorldPage
update_world (world_id, **fields) WorldResult
result = backend.create_world(name="Aldoria", description="Kingdom of runes")
result.id       # Weltenhub UUID
result.ok       # True on success
result.error    # str | None
result.backend  # "weltenhub"

Characters

Method Signature Returns
create_character (world_id, name, personality, backstory, is_protagonist, **kw) CharacterResult
get_character (character_id) CharacterResult
list_characters (world_id, page) CharacterPage
chars = backend.list_characters(world_id="<uuid>")
for c in chars.results:
    print(c.name, c.role_name)

Locations

Method Signature Returns
create_location (world_id, name, description, parent_id, **kw) LocationResult
list_locations (world_id, page, page_size) LocationPage
locs = backend.list_locations(world_id="<uuid>")
for loc in locs.results:
    print(loc.name, loc.location_type_name, loc.full_path)

new_loc = backend.create_location(
    world_id="<uuid>", name="Eisenhain",
    description="A fortress city in the northern mountains.",
)

Stories

Method Signature Returns
create_story (world_id, title, synopsis, **kw) StoryResult
list_stories (world_id, page, page_size) StoryPage
stories = backend.list_stories(world_id="<uuid>")
for s in stories.results:
    print(s.title, s.status)

story = backend.create_story(world_id="<uuid>", title="Der Ruf der Runen")

Scenes

Method Signature Returns
create_scene (story_id, title, summary, order, **kw) SceneResult
list_scenes (story_id, page, page_size) ScenePage
scenes = backend.list_scenes(story_id="<uuid>")
for s in scenes.results:
    print(s.title, s.location_name, s.order)

Result Types

All result types are frozen dataclasses with an .ok property:

Type Key fields
WorldResult id, name, description, setting_era, genre_name
CharacterResult id, name, world_id, role_name, description, personality
LocationResult id, name, world_id, parent_id, location_type_name, description, full_path
SceneResult id, title, story_id, summary, location_name, order
StoryResult id, title, world_id, genre_name, status, synopsis

All *Page types have .results: list[*Result] and .count: int.


User Provisioning (S2S, idempotent)

token = WeltenhubBackend.provision_user(
    username="bf_hugo",
    email="hugo@example.com",
    base_url="https://weltenforger.com/api/v1",
    service_token=WELTENHUB_API_KEY,
)
# Returns per-user token (Scenario A) or None on failure

LocalWorldBackend (tests / offline)

from weltenfw.backends.local import LocalWorldBackend

backend = LocalWorldBackend()
result = backend.create_world(name="Test")
# result.id = "" — caller manages local DB
# result.backend = "local"

Custom Backend (Protocol)

Implement AbstractWorldBackend without inheriting — structural subtyping:

from weltenfw.backends.base import AbstractWorldBackend, WorldResult

class MyBackend:
    def create_world(self, name: str, **kw) -> WorldResult: ...
    def get_world(self, world_id: str) -> WorldResult: ...
    def list_worlds(self, search: str = "", page: int = 1): ...
    def update_world(self, world_id: str, **fields): ...
    def create_character(self, world_id, name, **kw): ...
    def get_character(self, character_id): ...
    def list_characters(self, world_id, page=1): ...
    def list_locations(self, world_id, page=1, page_size=100): ...
    def create_location(self, world_id, name, **kw): ...
    def list_stories(self, world_id, page=1, page_size=100): ...
    def create_story(self, world_id, title, **kw): ...
    def list_scenes(self, story_id, page=1, page_size=100): ...
    def create_scene(self, story_id, title, **kw): ...

Architecture

  • 1 Client = 1 Token = 1 Tenant — no global singleton; multi-tenant callers instantiate one client per token.
  • Pydantic v2 — all API responses validated into typed, frozen schemas.
  • Separate Input schemas*CreateInput (POST) / *UpdateInput (PATCH).
  • Lookup cache — pluggable CacheBackend (NullCache → MemoryCache → DjangoCache).
  • Storage Backend Pattern — Weltenhub-DB is SSoT; consumer apps store UUID only.

Changelog

See CHANGELOG.md.

Links

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

iil_weltenfw-0.4.3.tar.gz (37.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

iil_weltenfw-0.4.3-py3-none-any.whl (37.0 kB view details)

Uploaded Python 3

File details

Details for the file iil_weltenfw-0.4.3.tar.gz.

File metadata

  • Download URL: iil_weltenfw-0.4.3.tar.gz
  • Upload date:
  • Size: 37.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for iil_weltenfw-0.4.3.tar.gz
Algorithm Hash digest
SHA256 34bbc67ce6a4853d8345e5716cc32937fc495f8684437f570297961517420f2c
MD5 206875ad9a76d3d48237fc1acebbc40e
BLAKE2b-256 869ded2853446362a4674c41bf1bdeca739d019d45c619ddda61d7f6d35b05b0

See more details on using hashes here.

File details

Details for the file iil_weltenfw-0.4.3-py3-none-any.whl.

File metadata

  • Download URL: iil_weltenfw-0.4.3-py3-none-any.whl
  • Upload date:
  • Size: 37.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for iil_weltenfw-0.4.3-py3-none-any.whl
Algorithm Hash digest
SHA256 849ebb14eacede10847b9b512eb8daac1a7c1b7fb24d081d9d645b17c96e99e9
MD5 3903863ecde5a9938748e8615e57bda2
BLAKE2b-256 1c6a70663d410dcf9f97dc98c4d6adc3d39d55d94576a17474c4f241907648f1

See more details on using hashes here.

Release history Release notifications | RSS feed

0.5.0

2 files

0.4.4

2 files

This release

0.4.3 This release

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.3.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page