Skip to main content

Python client for the Kanka API

Project description

python-kanka

A modern Python client for the Kanka API, the collaborative worldbuilding and campaign management platform.

Originally inspired by/forked from Kathrin Weihe's python-kanka. Thank you to Kathrin for the foundation and inspiration.

Features

  • Entity Support: Support for 12 core Kanka entity types:
    • Characters, Locations, Organisations, Families
    • Calendars, Events, Quests, Journals
    • Notes, Tags, Races, Creatures
  • Type Safety: Built with Pydantic v2 for data validation and type hints
  • Python 3.9+: Full typing support for modern Python versions
  • Pythonic API: Consistent interface patterns across all entity types
  • Error Handling: Specific exception types for different API errors
  • Rate Limit Handling: Automatic retry with exponential backoff
  • Entity Posts: Support for entity posts/comments management
  • Filtering and Search: Filter entities by various criteria and search across types
  • Pagination: Built-in pagination support for large result sets

Installation

Install from PyPI:

pip install python-kanka

From Source (using uv)

git clone https://github.com/ervwalter/python-kanka.git
cd python-kanka
uv sync --all-groups
uv pip install -e .

From Source (using pip)

git clone https://github.com/ervwalter/python-kanka.git
cd python-kanka
pip install -r requirements.txt
pip install -r dev-requirements.txt
pip install -e .

Quick Start

from kanka import KankaClient

# Initialize the client
client = KankaClient(
    token="your-api-token",      # Get from https://app.kanka.io/settings/api
    campaign_id=12345            # Your campaign ID
)

# Create a character
gandalf = client.characters.create(
    name="Gandalf the Grey",
    title="Wizard",
    type="Istari",
    age="2000+ years",
    is_private=False
)

# Update the character
gandalf = client.characters.update(
    gandalf,
    name="Gandalf the White"
)

# Search across all entities
results = client.search("Dragon")
for result in results:
    print(f"{result.name} ({result.type})")

# List characters with filters
wizards = client.characters.list(
    type="Wizard",
    is_private=False
)

# Delete when done
client.characters.delete(gandalf)

Common Use Cases

Working with Entity Posts

# Get a character
character = client.characters.get(character_id)

# Create a new post/note (pass the entity object, not just ID)
post = client.characters.create_post(
    character,  # Pass the full entity object
    name="Background",
    entry="*Born in the ancient times...*",
    is_private=False
)

# List all posts for an entity
posts = client.characters.list_posts(character)
for post in posts:
    print(f"{post.name}: {post.entry[:50]}...")

# Update a post (name field is required even if not changing)
update = client.characters.update_post(
    character,
    post.id,
    name=post.name,  # Required by API
    entry="Updated content..."
)

Advanced Filtering

# Filter by multiple criteria
results = client.characters.list(
    name="Gandalf",          # Partial name match
    type="Wizard",           # Exact type match
    is_private=False,        # Only public entities
    tags=[15, 23],          # Has specific tags
    page=1,                 # Pagination
    limit=30                # Results per page
)

# Access the generic entities endpoint
entities = client.entities(
    types=["character", "location"],  # Multiple entity types
    name="Dragon",                    # Name filter
    tags=[15, 23],                   # Tag filter
    is_private=False
)

Working with Multiple Entity Types

All entity types follow the same pattern:

# Locations
rivendell = client.locations.create(
    name="Rivendell",
    type="City",
    parent_location_id=middle_earth.id
)

# Organizations
council = client.organisations.create(
    name="The White Council",
    type="Council"
)

# Journals
journal = client.journals.create(
    name="Campaign Log",
    date="3019-03-25"
)

# Notes (for DM/private notes)
note = client.notes.create(
    name="DM Notes",
    entry="Remember: Gandalf knows about the ring",
    is_private=True
)

# Tags
tag = client.tags.create(
    name="Important NPC",
    colour="#ff0000"
)

Error Handling

from kanka.exceptions import (
    NotFoundError,
    ValidationError,
    RateLimitError,
    AuthenticationError
)

try:
    character = client.characters.get(99999)
except NotFoundError:
    print("Character not found")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except ValidationError as e:
    print(f"Invalid data: {e.errors}")
except AuthenticationError:
    print("Invalid API token")

Rate Limiting

The client automatically handles API rate limits by retrying requests with exponential backoff:

# Default behavior - automatic retry on rate limits
client = KankaClient(token, campaign_id)

# Disable automatic retry
client = KankaClient(
    token,
    campaign_id,
    enable_rate_limit_retry=False
)

# Customize retry behavior
client = KankaClient(
    token,
    campaign_id,
    max_retries=5,              # Try up to 5 times (default: 3)
    retry_delay=2.0,            # Initial delay in seconds (default: 1.0)
    max_retry_delay=120.0       # Maximum delay between retries (default: 60.0)
)

The client parses rate limit headers from the API to determine retry delays and respects the API's rate limits.

Migration Guide

Upgrading from v0.x to v2.0

The v2.0 release introduces a new API design with Pydantic models and type safety. Here's how to migrate:

Old API (v0.x)

# Old way - procedural API
import kanka
client = kanka.KankaClient(token)
campaign = client.campaign(campaign_id)
char = campaign.character(char_id)
char.name = "New Name"
char.update()

New API (v2.0+)

# New way - object-oriented with managers
from kanka import KankaClient
client = KankaClient(token, campaign_id)
char = client.characters.get(char_id)
char = client.characters.update(char, name="New Name")

Key Differences

  1. Single Client: No more separate campaign object - everything through KankaClient
  2. Entity Managers: Each entity type has a dedicated manager (client.characters, client.locations, etc.)
  3. Immutable Models: Models are Pydantic objects - use manager methods to update
  4. Better Types: Full typing support with IDE autocomplete
  5. Consistent API: All entities follow the same CRUD pattern

Development Setup

For development, install additional dependencies:

# Clone the repository
git clone https://github.com/ervwalter/python-kanka.git
cd python-kanka

# Install dev dependencies
pip install -r dev-requirements.txt
pip install -e .  # Install in editable mode

Development Tools

This project uses several tools to maintain code quality:

  • black - Code formatter
  • isort - Import sorter
  • ruff - Fast Python linter
  • pytest - Testing framework
  • mypy - Static type checker

Use the Makefile for common development tasks:

make install   # Install all dependencies
make format    # Format code with black and isort
make lint      # Run linting checks
make test      # Run all tests
make coverage  # Run tests with coverage report
make check     # Run all checks (lint + test)
make clean     # Clean up temporary files

Pre-commit Hooks (Optional)

To automatically run formatting and linting before each commit:

pre-commit install

API Documentation

See the API Reference for detailed documentation of all classes and methods.

Examples

Check out the examples/ directory for more detailed examples:

  • quickstart.py - Basic usage tutorial
  • crud_operations.py - Full CRUD examples for all entity types
  • filtering.py - Advanced filtering and search
  • posts.py - Working with entity posts
  • error_handling.py - Proper error handling patterns
  • migration.py - Migrating from the old API

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Links

Project details


Download files

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

Source Distribution

python_kanka-2.3.0.tar.gz (149.2 kB view details)

Uploaded Source

Built Distribution

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

python_kanka-2.3.0-py3-none-any.whl (23.9 kB view details)

Uploaded Python 3

File details

Details for the file python_kanka-2.3.0.tar.gz.

File metadata

  • Download URL: python_kanka-2.3.0.tar.gz
  • Upload date:
  • Size: 149.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for python_kanka-2.3.0.tar.gz
Algorithm Hash digest
SHA256 593f125e4dcce5d95e2b10cc9f06b0a98e14aee614df7868c9e44f0d7d4ec28f
MD5 a466f81d365ac5d9332ac9efe394ee45
BLAKE2b-256 ed135c15219c1a97ac324e523ac13eeda72df7fe92e374f10edd1c790144f02f

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_kanka-2.3.0.tar.gz:

Publisher: publish.yml on ervwalter/python-kanka

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_kanka-2.3.0-py3-none-any.whl.

File metadata

  • Download URL: python_kanka-2.3.0-py3-none-any.whl
  • Upload date:
  • Size: 23.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for python_kanka-2.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 61d70ba4a5fc1d72af880304056db93221e80080bded5dcb93af652565c56b4b
MD5 cea395c2d5cc9af10c480a5ee9627abc
BLAKE2b-256 e7e3230b7c4dabdff4ed0854eaa43e47dfda126f7ad6ecf16401686b2261098e

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_kanka-2.3.0-py3-none-any.whl:

Publisher: publish.yml on ervwalter/python-kanka

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page