Skip to content

Configuration

PyJinHx provides several configuration options for customizing template discovery and rendering behavior.

Default Environment

The default Jinja environment controls where templates are loaded from.

Auto-Detection

By default, PyJinHx walks upward from the current directory to find your project root:

from pyjinhx import Renderer

# Auto-detects project root
renderer = Renderer.get_default_renderer()

Project root is detected by looking for common markers:

  • pyproject.toml
  • main.py
  • .git
  • .gitignore
  • package.json
  • uv.lock

Setting a Custom Path

from pyjinhx import Renderer

# Set explicit template path
Renderer.set_default_environment("./components")

# Now all components look for templates under ./components

Using a Jinja Environment

For full control, pass a Jinja Environment:

from jinja2 import Environment, FileSystemLoader
from pyjinhx import Renderer

env = Environment(
    loader=FileSystemLoader("./templates"),
    autoescape=True,
    trim_blocks=True,
    lstrip_blocks=True,
)

Renderer.set_default_environment(env)

Clearing the Default

Renderer.set_default_environment(None)  # Reset to auto-detection

Logging

PyJinHx uses Python's standard logging:

import logging

# Enable debug logging
logging.getLogger("pyjinhx").setLevel(logging.DEBUG)

Logged events include:

  • Component class registration warnings (duplicates)
  • Component instance registration warnings (ID conflicts)

Application setup

For web apps, use a single call:

from pyjinhx import setup

setup(app, context_factory=lambda req: AppLoadContext(db=get_db(req)))

PjxSettings has two fields:

  • invalidation_backend — cross-worker invalidation backend (default None)
  • reactive_dev — enable reactive dev guardrails (default False)

The load-cache scope is derived from invalidation_backend: a backend (e.g. Redis) makes cross-request caching safe across workers, so load() results are cached per worker process; without one, they are cached per request only — the only multi-worker-safe default.

Pass a settings object via settings=, or override individual fields with explicit setup() keyword arguments. Explicit setup() kwargs take precedence over values from settings=.

Environment variables

PjxSettings.from_env() builds settings from the environment:

  • REDIS_URL — wires a RedisInvalidationBackend (which derives cross-request caching)
  • PJX_INVALIDATION_DB — wires a SqliteInvalidationBackend with the given path (used when REDIS_URL is not set)
  • PJX_REACTIVE_DEV — enables reactive dev mode when set to 1, true, or yes
from pyjinhx import PjxSettings, setup

setup(app, settings=PjxSettings.from_env())

See Configuration API for PjxSettings, lifespan chaining, and cache defaults.

Load cache scope

You don't pick a scope — it follows the backend. By default (no invalidation_backend), load() results are cached per request only, the only multi-worker-safe behavior. Configure a cross-worker backend to opt into cross-request caching per worker process:

from pyjinhx import setup

setup(app)  # per-request caching (default, multi-worker safe)
setup(app, invalidation_backend=...)  # cross-request per worker; see integrations.redis

Registry.request_scope() initializes a request-scoped cache on entry and clears it on exit. With a backend configured, reads also use the process-wide store; otherwise only the request store is used. Within-request caching always happens — it dedups the repeated load() calls of the reactive OOB walk.

See Cache & Invalidation and Reactivity.

Invalidation fan-out

For multi-worker production, set a cross-worker invalidation_backend so invalidate() fans out to every process (and enables cross-request caching):

from pyjinhx import PjxSettings, setup
from pyjinhx.integrations.redis import RedisInvalidationBackend

setup(
    app,
    settings=PjxSettings(
        invalidation_backend=RedisInvalidationBackend("redis://..."),
    ),
)

See Cache & Invalidation and Redis integration.

Reactive dev mode

Enable development guardrails to catch common reactive mistakes:

from pyjinhx.dev import enable_reactive_dev, disable_reactive_dev

enable_reactive_dev()           # log warnings
enable_reactive_dev(strict=True)  # raise RuntimeError instead
disable_reactive_dev()

Guardrails cover: mutations without a consuming render(), dirtied keys without mounted, and depends_on() outside the static react superset.

Inspect the dependency graph with dependency_graph() or format_dependency_graph(). See Mutations, Keys & PjxContext.