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.4.tar.gz (37.5 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.4-py3-none-any.whl (37.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: iil_weltenfw-0.4.4.tar.gz
  • Upload date:
  • Size: 37.5 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.4.tar.gz
Algorithm Hash digest
SHA256 120242529cec585bc75168cbd1f9802e87263d1a48c7a476eba16f61f0404d09
MD5 705af0c2f76b3704299ce1ad7bdf64fb
BLAKE2b-256 4735d77c0eec96c58f518725c1031ddf4f5f88265c5092d7148f2fdeb8d1cc36

See more details on using hashes here.

File details

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

File metadata

  • Download URL: iil_weltenfw-0.4.4-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.4-py3-none-any.whl
Algorithm Hash digest
SHA256 a82aed9ebd16bb773854bcdd129fc82c3af6e814f4040b37c67199684797ea40
MD5 389da3215934f3d0bed5e2103f6b9a50
BLAKE2b-256 b09a461c470d2a060df2af20188b25562b9278f851de7b3b421ff788fe554e41

See more details on using hashes here.

Release history Release notifications | RSS feed

0.5.0

2 files

This release

0.4.4 This release

2 files

0.4.3

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