Skip to main content

Reusable runtime configuration, config CLI, and logging helpers for Python applications.

Project description

apprc: Application Runtime Config

Part of:

logo

uv Python 3.12+

Ruff Pyright pytest

apprc is a small Python library for application runtime configuration and logging. It is useful when a project needs typed env-backed config, packaged defaults, per-user storage registries, local override files, a reusable config CLI, a terminal config editor, and structured logs without rebuilding that plumbing in every application.

The key idea: the application declares its config contract once, and apprc derives the boring workflows from that contract.

Tech Stack:


Installation

Important

Prerequisites


Install From PyPI

python -m pip install apprc

Use apprc As Project Dependency

Any Python build system supporting pyproject.toml (PEP 621) works.

For published releases, depend on the PyPI package:

[project]
dependencies = [
    "apprc",
]

For the current repository revision, depend on the Git URL:

[project]
dependencies = [
    "apprc @ git+https://github.com/HisQu/apprc.git",
]

Editable Install With pip

git clone https://github.com/HisQu/apprc.git
cd apprc

python -m venv .venv
source .venv/bin/activate
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -e "." --group dev

Editable Install With uv

git clone https://github.com/HisQu/apprc.git
cd apprc

uv sync --frozen --all-groups

Verify

python -c "import apprc; print(apprc.AppConfigKit)"
pytest

Example

An application usually wires AppRC in three steps: declare fields, create the kit, and mount the generated config CLI.

from dataclasses import dataclass

import typer

from apprc import AppConfigKit
from apprc.config import ConfigOwner, config_field

# 1) Declare the config fields your app owns.
CLIENT_OWNER = ConfigOwner(
    key="client",
    title="Client",
    env_prefix="MYAPP_",
    rc_path=("client",),
    runtime_cls=None,
    fields=(
        config_field(
            "model",
            "MODEL",
            str,
            default="demo-model",
            title="Model",
            explanation="Model used by client calls.",
        ),
    ),
)

# 2) Create the reusable AppRC facade for your application.
MYAPP_CONFIG = AppConfigKit(
    app_name="myapp",
    display_name="MyApp",
    config_package="myapp.config",
    owners=(CLIENT_OWNER,),
    storage_root_env_key="MYAPP_D_STORAGE",
    registry_filename="myapp.toml",
    shared_env_filename=".env.shared",
    local_env_filename=".env.local",
)

# 3) Mount the generated `myapp config ...` command group.
@dataclass(slots=True)
class CliState:
    env_bootstrap: object | None = None
    storage: str | None = None


app = typer.Typer()
app.add_typer(
    MYAPP_CONFIG.typer_app(state_type=CliState),
    name="config",
)

Runtime dataclasses can inherit BaseEnv when you want typed objects populated from the bootstrapped environment. The important first step is the owner inventory: AppRC reuses it for loading, validation, docs, CLI commands, and the terminal editor.

AppRC does not install its own apprc command. The config CLI is meant to be mounted as a subcommand of the application that depends on AppRC.

Users then get:

myapp config setup
myapp config init /absolute/path/to/storage --name default --default
myapp config doctor
myapp config show --json
myapp config set client.model other-model
myapp config edit

Use myapp config setup for normal first-time installation. It explains the config file and storage root locations, asks for a default storage, and prints next steps. config init remains available as the lower-level command for scripts or manual storage registration.


Explanations

Config Model

apprc separates config into clear layers:

Layer Owner Purpose
ConfigField application One typed env-backed setting.
ConfigOwner application A named section of related fields.
.env.shared application package Packaged defaults shipped with code.
<storage>/.env.local user/project Per-storage local overrides.
shell environment user/process Highest-priority process values by default.
~/.config/<app>/<registry_filename> AppRC registry Named storage roots and default storage.

Runtime dataclasses inherit BaseEnv. The dataclass owns Python attributes; ConfigOwner owns env names, docs labels, editor labels, choices, and redaction metadata.

Bootstrap Precedence

Applications call AppConfigKit.bootstrap(...) once at CLI startup. It merges:

  1. packaged .env.shared
  2. selected storage-local .env.local
  3. explicit --env-file
  4. current shell environment

By default, the shell wins over --env-file. Set env_file_overrides_shell=True when an explicit file should win inside the current process.

Storage Registries

Globally installed commands need to find user data without hardcoding one path. apprc stores named roots in ~/.config/<app>/<registry_filename>, unless the app-specific <APP>_CONFIG_FILE environment variable points to a custom TOML file. For an app named myapp, that override is MYAPP_CONFIG_FILE. The interactive setup command refuses custom locations unless that variable is already set, because future commands must be able to rediscover the same file. For example:

default_storage = "default"

[storages.default]
root = "/absolute/path/to/storage"

[archived_storages.old-default]
archive = "/absolute/path/to/old-default.apprc.tar.xz"
source_root = "/absolute/path/to/old-default"

Each storage root owns its own local override file, such as .env.local. Archived storage records are only last-known restore shortcuts for the terminal editor; runtime bootstrap still selects live directory entries from [storages]. On POSIX/WSL hosts, Windows drive paths such as D:\Training\demo-project are normalized to usable local paths before AppRC writes the registry or reads a storage-root environment value.

Important

POSIX shells consume unquoted backslashes before Python sees the argument. If you type C:\Projects\demo-storage without quotes, AppRC may receive C:Projectsdemo-storage, which is not recoverable as a real Windows path. Use one of these forms instead:

myapp config init 'C:\Projects\demo-storage' --name default --default
myapp config init C:/Projects/demo-storage --name default --default
myapp config init /mnt/c/Projects/demo-storage --name default --default

Logging

apprc.logging wraps stdlib logging and structlog. setup_logging() installs formatters and dependency logger levels. get_logger() returns an AppLogger with semantic helper methods such as action_begin, success, retry, fallback, telemetry, and traceback.

Use AppRC logging when application logs should stay structured and readable in CLI output, notebooks, and tests.


Guides

Define Config Fields

Put config declarations in your application package, usually myapp/config/owners.py.

from pathlib import Path

from apprc.config import CONFIG_MISSING, ConfigOwner, config_field

STORAGE_OWNER = ConfigOwner(
    key="storage",
    title="Storage",
    env_prefix="MYAPP_",
    rc_path=("storage",),
    runtime_cls=None,
    fields=(
        config_field(
            "root",
            "D_STORAGE",
            Path,
            default=CONFIG_MISSING,
            editable=False,
            required=True,
            explanation_short="Active storage root.",
            explanation_long="Selected through the AppRC storage registry.",
        ),
    ),
)

Use editable=False for values owned by the registry instead of .env.local.

Bootstrap a CLI

Call bootstrap before creating runtime config objects.

from apprc.cli import bootstrap_cli_env
from apprc.logging import setup_logging

state.env_bootstrap = bootstrap_cli_env(
    MYAPP_CONFIG,
    env_file=env_file,
    env_file_overrides_shell=env_file_overrides_shell,
    no_dotenv=no_dotenv,
    storage_name=storage,
    log_level=log_level,
    setup_logging=setup_logging,
)

Add the Generated Config CLI

config_app = MYAPP_CONFIG.typer_app(
    state_type=CliState,
    runtime_payload=lambda state: {
        "storage": str(state.env_bootstrap.storage_root)
        if state.env_bootstrap
        else None,
    },
)
app.add_typer(config_app, name="config")

Edit Local Values in the Terminal

config edit opens a Textual editor. The editor shows:

  • key number
  • section
  • env key
  • shell status
  • local value
  • default value
  • short explanation

Selecting a row opens a modal with type information, possible values, and the long explanation. Secret values are redacted. Required missing values show <required>.

The editor also manages storage lifecycle:

  • New storage registers a directory or restores a *.apprc.tar.xz archive.
  • Set this as default storage changes the registry default.
  • Delete storage can unregister only or delete the directory too.
  • Archive storage writes *.apprc.tar.xz and can optionally remove the source directory after compression.

If the last live default is removed, the editor prompts for a replacement path prefilled with ~/.local/share/<app>/default or offers to leave AppRC in the fresh-install state with no default storage.

Use Logging

from apprc.logging import get_logger, setup_logging

setup_logging(level="INFO", renderer="cli")
log = get_logger(__name__)

log.action_begin("Loading workspace")
log.success("Workspace ready", storage="default")

References

Important Modules

Module Look Here For
apprc.config.schema ConfigField, ConfigOwner, field lookup, typed loading.
apprc.config.kit AppConfigKit, the high-level app integration facade.
apprc.config.environment CLI startup dotenv/bootstrap precedence.
apprc.config.paths Storage-root path normalization helpers.
apprc.config.storage_registry ~/.config/<app>/*.toml storage names.
apprc.config.storage_archive *.apprc.tar.xz storage compression and restore.
apprc.config.local_env <storage>/.env.local reads, writes, validation.
apprc.config.tui Textual app and modal interactions.
apprc.config.tui_rendering Pure table cell rendering and styles.
apprc.cli.config_app Generated config Typer commands.
apprc.cli.bootstrap Common root CLI bootstrap options.
apprc.logging Logging facade: setup_logging, get_logger, AppLogger.

Important Config Types

Type Meaning
AppConfigKit Convenient object applications keep around.
AppConfigSpec Frozen declaration behind the kit.
ConfigOwner One config section, env prefix, runtime path, and fields.
ConfigField One editable or read-only env-backed setting.
BaseEnv Runtime dataclass base that binds values from env.
EnvBootstrapResult Files and storage selected during CLI startup.
StorageRegistry Parsed TOML registry.
ArchivedStorageRecord Last-known archive path for editor restore shortcuts.
LocalEnvUpdate Result of writing one local dotenv override.

Config CLI Commands

Command Purpose
config setup Interactively choose the registry file and default storage.
config init STORAGE_ROOT --name NAME --default Register a storage root.
config doctor Diagnose registry and selected storage state.
config show --json Print resolved runtime config payload.
config set-default NAME Change default storage.
config set KEY VALUE Write one local override.
config edit Open the Textual editor.

Logging Functions

Function Purpose
setup_logging(...) Configure stdlib/structlog output.
get_logger(__name__) Return an AppLogger.
log.action_begin(...) Start a visible operation.
log.success(...) Mark a completed operation.
log.retry(...) Record retry attempts.
log.fallback(...) Record fallback behavior.
log.traceback(...) Emit exception information with redaction support.
async_telemetry(...) Emit periodic async progress logs.

Development

Local Setup

git clone https://github.com/HisQu/apprc.git
cd apprc

python -m venv .venv
source .venv/bin/activate
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -e "." --group dev

or:

uv sync --frozen --all-groups

Quality Gates

Run these before sending changes:

ruff format .
ruff check .
pyright
pytest

Test Against Haiu

Haiu is the main downstream integration test for AppRC. From the Haiu repo:

cd ../haiu
.venv/bin/python -m pip install --no-deps --no-build-isolation -e ../apprc
.venv/bin/pytest tests/haiu/core/test_config_tui.py -q
.venv/bin/pytest

Keep refactors behavior-preserving. If a cleanup would remove a public module, change import-time side effects, or alter CLI output, treat that as a feature change and ask first.

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

apprc-0.2.1.tar.gz (92.7 kB view details)

Uploaded Source

Built Distribution

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

apprc-0.2.1-py3-none-any.whl (99.8 kB view details)

Uploaded Python 3

File details

Details for the file apprc-0.2.1.tar.gz.

File metadata

  • Download URL: apprc-0.2.1.tar.gz
  • Upload date:
  • Size: 92.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"44","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for apprc-0.2.1.tar.gz
Algorithm Hash digest
SHA256 983232b24bde5eacbb00ded73845b188c55f2cca29f1e8a3582209ead700588c
MD5 64d9c54550c00d1c0477aabd73f588f4
BLAKE2b-256 1b8cb5ec1c809e4bb6ac57ea55d3a1898027d8b7ddf74c7193e629a3a0d196c3

See more details on using hashes here.

File details

Details for the file apprc-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: apprc-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 99.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"44","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for apprc-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 84c0015ecb3288538abe90126f4a914bb2e85887959161ad70b3ceee51650b9a
MD5 444e811e8dfb3d288af16ce6be28d112
BLAKE2b-256 7caa6aca5580581f7b8879af1a2fd6d26b4af95c59f592825c5c4fdded37bd2f

See more details on using hashes here.

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