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.

Metadata

Release files for iil-weltenfw 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for iil-weltenfw 0.5.0
File Size Uploaded Provenance
iil_weltenfw-0.5.0.tar.gz 40.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for iil-weltenfw 0.5.0
File Interpreter ABI Platform
iil_weltenfw-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 78.3 kB

Release files / iil_weltenfw-0.5.0.tar.gz

Download URL iil_weltenfw-0.5.0.tar.gz
Size 40.0 kB
Tags Source
SHA-256 checksum
How to use checksums
70e5b9c5da93046043289d03e074720863b51518844c3b6cc82acd475413d8c1
BLAKE2b-256 checksum
How to use checksums
8b57900634a5e56ee2dd964998e85450ad649361f5ac4d46243c17a2c9d4f294
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 21, 2026.

Transparency log

Release files / iil_weltenfw-0.5.0-py3-none-any.whl

Download URL iil_weltenfw-0.5.0-py3-none-any.whl
Size 38.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bc87759daecb7fc3ff7c10fb51705b8c22abf7b6f8376e92585d38ed5ce56226
BLAKE2b-256 checksum
How to use checksums
40009d1073164a8a02d9a5f689e2b5c35c1eefe2a654a151f5d9d9a63859d4e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 21, 2026.

Transparency log

Security for iil-weltenfw 0.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for iil_weltenfw-0.5.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 21, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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