Reusable runtime configuration, config CLI, and logging helpers for Python applications.
Project description
apprc: Application Runtime Config
AppRC is for Python applications that need configuration to be explicit, inspectable, and pleasant to operate. Instead of spreading environment variables, dotenv files, setup commands, and diagnostics across unrelated code, you declare the runtime contract once and let AppRC build the surrounding workflows from that metadata.
The three strongest parts:
- Typed config contracts: declare application settings once with
EnvConfig,env_field(...), and@env_owner(...). - Deterministic runtime config: load layered dotenv files predictably while keeping normal runtime reads and diagnostics zero-write.
- Generated operator UX: mount ready-made Typer
configcommands and open the same contract in the Textual editor.
Fig. 1 - AppRC Graphical Abstract: AppRC lets developers ship one typed config contract with generated setup, diagnostics, editing, and runtime config workflows.
Note
For the full system model, see docs/Explanations.md. For exact public names and command references, see docs/References.md.
Table Of Contents
apprc: Application Runtime Config- Installation
- Quickstart
- How AppRC Works
- Generated Workflows
- More Documentation
Install AppRC, declare the runtime contract, and mount the generated config
commands in your Typer application.
Installation
python -m pip install apprc
Install optional structured logging support when your app calls
setup_logging():
python -m pip install "apprc[logging]"
AppRC supports Python 3.12 and newer.
Note
For installation and first-setup recipes, see docs/How-To-User-Guides.md. Optional logging APIs are listed in docs/References.md#optional-logging-apis.
Quickstart
Declare typed config sections with EnvConfig, @env_owner, and
env_field(...):
from pathlib import Path
from apprc import AppConfigKit, EnvConfig, env_field, env_owner
@env_owner(
key="app",
title="App",
env_prefix="MYAPP_",
rc_path=("app",),
)
class MyAppEnv(EnvConfig):
storage_root: Path = env_field(
"STORAGE",
editable=False,
required=True,
title="Storage root",
)
profile: str = env_field(
"PROFILE",
default="default",
title="Profile",
explanation_short="Named runtime profile.",
)
access_token: str = env_field(
"ACCESS_TOKEN",
required=True,
secret=True,
title="Access token",
)
APP_CONFIG = AppConfigKit.storage_only(
app_name="myapp",
display_name="My App",
config_package="myapp.config",
envs=(MyAppEnv,),
)
Add packaged defaults in myapp/config/.env.shared:
MYAPP_PROFILE="default"
Bootstrap your app before constructing runtime config objects:
import typer
from apprc.cli import mount_config_cli
from myapp.config import APP_CONFIG, MyAppEnv
app = typer.Typer()
mount_config_cli(app, APP_CONFIG)
@app.command()
def run() -> None:
cfg = MyAppEnv()
typer.echo(f"profile={cfg.profile}")
mount_config_cli(...) adds the standard AppRC host-level options, performs
runtime bootstrap for commands that need resolved config, and mounts the generated
config command group. Apps with custom runtime state can pass
state_type=... and state_factory=...; tests or lazy-forwarding CLIs can pass
args_provider=... with tokens shaped like CliArgvProvider. Apps whose
config hooks must run for config set or config edit can pass
bootstrap_policy=.... Use config_group_name=... only when the generated
group should not be named config; AppRC raises a clear error if the host app
already owns that command or group name.
Apps that own their host callback and extra options can use ConfigCliBridge
as the composable middle layer: the app builds its runtime state, while AppRC
owns config command mounting, skip policy, context storage, and state
validation. When bridge.prepare(...) skips runtime bootstrap,
session.skipped_runtime_bootstrap is true and session.state is None.
Runtimeful generated config commands require the host callback to leave the
declared state_type on ctx.obj; bootstrapless config commands use AppRC's
stored context instead.
Note
For the step-by-step integration guide, see docs/How-To-User-Guides.md#2-integrate-apprc. For the exact import surface, see docs/References.md#public-interfaces.
How AppRC Works
AppRC starts from one declared contract, then uses that contract to load runtime values, inspect configuration health, write explicit setup files, and generate user-facing configuration tools.
| Fig. 2 - One Contract, Many Workflows: AppRC reuses the same contract metadata for runtime loading, provenance, diagnostics, generated CLI commands, and the editor. |
Mental Model
AppRC has one contract and several workflows built from it.
| Concept | Meaning |
|---|---|
| Config field | One typed setting declared with env_field(...). |
| Config owner | A related group of fields declared by @env_owner(...). |
| App config kit | The app-level contract that selects supported persistence layers. |
| Bootstrap | A startup step that merges dotenv layers into this Python process. |
| Generated CLI | A reusable Typer config command group for inspection and edits. |
| Editor | A Textual view over the same owners, fields, and dotenv layers. |
Note
For the deeper architecture behind owners, fields, capability layers, provenance, and the zero-write policy, see docs/Explanations.md#3-runtime-config-model.
Capability Layers
Choose one capability constructor:
| Constructor | Storage root | App-wide dotenv | Named storage index |
|---|---|---|---|
AppConfigKit.env_only(...) |
disabled | optional | disabled |
AppConfigKit.storage_only(...) |
required | optional | optional |
AppConfigKit.app_wide_config(...) |
disabled | default | disabled |
AppConfigKit.app_wide_storage(...) |
required | default | optional |
AppRC-managed persistence files are explicit:
| Layer | Default location | Created by |
|---|---|---|
| Packaged shared defaults | package .env.shared |
the application package |
| App-wide config | platform config home .env.apprc-app |
config app init, app-wide setup, or app-scope save |
| Storage config | <storage-root>/.env.apprc-storage |
storage setup, config storage add, or storage-scope save |
| Named-storage index | <config-home>/<app>.apprc.toml |
config storage add/remove |
Note
For constructor arguments and capability details, see docs/References.md#capability-constructors.
Runtime Precedence
When dotenv layers are loaded, AppRC merges values in this order:
- packaged
.env.shared - app-wide
.env.apprc-app, when allowed and present - selected storage
.env.apprc-storage, when storage is selected and present - explicit
--env-filevalues - existing
os.environ
With --env-file-overrides-os-environ, explicit env files move after
os.environ and win over shell exports.
Storage selector resolution uses:
- host-level
--storage - shell env, for example
MYAPP_STORAGE - explicit env files, respecting
--env-file-overrides-os-environ - app-wide
.env.apprc-app, when active - packaged
.env.shared
Path selectors work without a named-storage index. Bare named selectors use
<app>.apprc.toml when the index exists.
Note
For the rationale behind layer order and storage selector resolution, see docs/Explanations.md#runtime-bootstrap and docs/Explanations.md#storage-selection. For exact precedence tables, see docs/References.md#runtime-precedence.
Generated Workflows
Mount the generated workflows when you want your application to expose the same contract to users, setup commands, diagnostics, and the Textual editor.
Config CLI
Mounting APP_CONFIG.typer_app(...) gives your app these commands:
myapp config paths
myapp config doctor
myapp config show
myapp config setup
myapp config set KEY VALUE --scope app
myapp config set KEY VALUE --scope storage
myapp config edit
myapp config app init
myapp config storage add NAME PATH
myapp config storage list
myapp config storage remove NAME
The command group follows the selected capabilities. For example, storage-free apps do not expose named-storage commands.
Note
For the generated command table, see docs/References.md#generated-cli-commands.
Setup And Diagnostics
Use config paths before setup to see candidate paths and declared
capabilities without writing anything. Use config setup for explicit first
storage setup, then use config doctor when a machine is not runnable.
myapp config paths
myapp config setup --yes --storage-root /absolute/path/to/storage
export MYAPP_STORAGE="/absolute/path/to/storage"
myapp config doctor
myapp config set access_token secret-value --scope storage
myapp run
config doctor reports a status such as env_not_set, storage_not_ready,
app_config_not_ready, named_storage_not_ready, or runnable.
Important
Runtime reads and diagnostics do not create files. bootstrap, config paths, config doctor, and opening config edit are zero-write.
Note
For doctor troubleshooting, see docs/How-To-User-Guides.md#troubleshoot-config-doctor. For exact status names, see docs/References.md#doctor-statuses.
Optional Logging
AppRC also includes stdlib-compatible semantic logging helpers. The base
logger API imports without structlog; setup_logging() requires the
logging extra.
from apprc.logging import get_logger, setup_logging
setup_logging(level="INFO", renderer="cli")
log = get_logger(__name__)
log.success("configured", extra_struct={"profile": "default"})
Create application loggers with get_logger(name) or call
install_app_logger_class() before other code creates those names with
logging.getLogger(name). Existing plain stdlib logger instances cannot be
safely reclassed, so get_logger(name) raises RuntimeError for those names.
Note
For logging design context, see docs/Explanations.md#optional-logging. For import names and dependency details, see docs/References.md#optional-logging-apis.
More Documentation
The README stays short. The detailed manual and maintainer workflow live in the documentation directory.
Detailed Manual
The detailed manual starts at docs/README.md.
Note
Use docs/How-To-User-Guides.md for integration recipes, docs/Explanations.md for the AppRC system model, docs/References.md for exact commands, files, and APIs, and docs/Development.md for maintainer workflow and docs rules.
The repository also ships a runnable example app in examples/apprc_example_app.
Development
.venv/bin/ruff format .
.venv/bin/ruff check .
.venv/bin/pyright
.venv/bin/pytest
Regenerate the PyPI README after editing this file:
python src/apprc_dev/packaging/pypi_readme.py
Note
For maintainer workflow, documentation rules, and verification commands, see docs/Development.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file apprc-0.16.4.tar.gz.
File metadata
- Download URL: apprc-0.16.4.tar.gz
- Upload date:
- Size: 179.2 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35b3e9f0983caf3940edd21a828f04fe000898ba30282429ef0525f8af3ee1cf
|
|
| MD5 |
1bfed2de1222027a4745e200bf8e114b
|
|
| BLAKE2b-256 |
e2e2733f544ee65fa9a3ec1d11d8650cec4734704fc235232198b3d9e7935856
|
File details
Details for the file apprc-0.16.4-py3-none-any.whl.
File metadata
- Download URL: apprc-0.16.4-py3-none-any.whl
- Upload date:
- Size: 191.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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b16c2819523bc895e5e25095555f26e887164b633d29e2db6a6db242bdd9cb9
|
|
| MD5 |
95f0e2ab726f30af3df44f2075af462c
|
|
| BLAKE2b-256 |
80054e6ebf9aaa31992970811a3c2bfeb703eeb052a59bd6741c4af86f4a551e
|