Reusable runtime configuration, config CLI, and logging helpers for Python applications.
Project description
apprc: Application Runtime Config
apprc is a Python library for typed, env-backed application configuration. It
gives an app packaged defaults, optional app-wide dotenv config, optional
storage dotenv config, optional named storage roots, a generated Typer config
CLI, and a Textual editor.
Table Of Contents
- Installation
- Mental Model
- Developer API
- Runtime Precedence
- Generated CLI
- Upgrade Paths
- Filenames And Env Vars
- Development
Installation
python -m pip install apprc
Install optional structured logging support when the app calls
setup_logging():
python -m pip install "apprc[logging]"
Mental Model
AppRC now uses explicit persistence capability layers.
| Layer | File or selector | Writes by default? |
|---|---|---|
| Packaged shared defaults | package .env.shared |
never |
| Shell / explicit env files | os.environ, --env-file |
never |
| App-wide config | platform config home .env.apprc-app |
only config app init, config setup for app-wide constructors, or explicit app-scope saves |
| Storage config | <storage-root>/.env.apprc-storage |
only config setup, config storage add, or explicit storage-scope saves |
| Named-storage index | <app>.apprc.toml |
only config storage add/remove |
Runtime reads and diagnostics are zero-write. config paths, config doctor,
normal bootstrap, and opening the editor do not create files.
Important
AppRC no longer reads .env.global or .env.local. config doctor warns
when those legacy files are found and tells users to move values to
.env.apprc-app or .env.apprc-storage.
Developer API
Declare config fields with EnvConfig, then choose one constructor.
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)
profile: str = env_field("PROFILE", default="default")
APP_CONFIG = AppConfigKit.storage_only(
app_name="myapp",
display_name="My App",
config_package="myapp.config",
envs=(MyAppEnv,),
)
| Constructor | Storage layer | App-wide layer | 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 |
Use storage_env_key="MYAPP_STORAGE" only with storage-capable constructors.
Passing storage_mode= is removed and raises TypeError.
Public dotenv helpers use neutral env-file names:
EnvFileUpdateread_env_file(path)/write_env_file(path, values, owners=...)ensure_env_file(path)set_env_file_value(...)/clear_env_file_value(...)storage_env_path(root),ensure_storage_env_file(root),set_storage_env_value(...), andclear_storage_env_value(...)
The old LocalEnvUpdate, read_local_env, write_local_env,
local_env_path, set_local_env_value, and clear_local_env_value names are
removed.
Mount the generated config CLI:
config_app = APP_CONFIG.typer_app(state_type=MyCliState)
app.add_typer(config_app, name="config")
Runtime Precedence
When dotenv layers are loaded, values are merged in this order:
- packaged
.env.shared - app-wide
.env.apprc-app, only when the layer is allowed and the file exists - selected storage
.env.apprc-storage, only when storage is selected and the file exists - 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:
- root
--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
Named selectors resolve through <app>.apprc.toml only when named storage is
allowed and the index file exists. Path selectors work without an index file and
ignore corrupt optional indexes at runtime; config doctor reports those stray
index problems as warnings. Bare selectors need the index when it exists, so a
corrupt index is fatal for named-selector resolution.
Generated CLI
All commands below are shown with myapp as the application command name.
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
Removed commands:
myapp config initmyapp config list
Use myapp config storage add NAME PATH and
myapp config storage list instead.
config paths
config paths is always zero-write. It reports declared capabilities, active
layers, candidate paths, existing files, selected storage, named-storage index
status, and writes: none.
config setup
config setup follows the constructor:
| Constructor | Setup behavior |
|---|---|
env_only |
prints env guidance; writes nothing |
storage_only |
asks for or accepts --storage-root; creates .env.apprc-storage; prints export MYAPP_STORAGE=... |
app_wide_config |
creates .env.apprc-app |
app_wide_storage |
creates .env.apprc-app and selected storage .env.apprc-storage |
Optional upgrades are separate commands, not setup prompts.
config set
config set writes to app-wide or storage dotenv files.
- If exactly one writable layer is active,
--scopemay be omitted. - If app-wide and storage are both active, pass
--scope appor--scope storage. - Env-only apps have no writable scope until an app-wide file is explicitly
initialized with
config app init.
config set skips runtime bootstrap so --scope app does not require storage
readiness. Storage is resolved only for --scope storage or when scope
inference needs to know whether storage is writable.
config edit
config edit is the primary interactive view. It opens without creating files
and shows source columns for Effective, Shell, App-wide, Storage,
Default, and Explanation.
- The app-wide column appears when the app-wide layer is default-active or when
.env.apprc-appexists. - The storage column appears when a storage root is selected; a missing
.env.apprc-storageis shown as empty until the user saves to storage. - Saving chooses
apporstoragewhen both are writable, and creates only the selected target file. - Named-storage controls are available only when named storage is enabled and an index is loaded; direct path-selected storage editing works without an index.
Upgrade Paths
Storage-only users can start with one env var:
export MYAPP_STORAGE="/absolute/path/to/storage"
That path selector does not require a named-storage index.
To add app-wide config later:
myapp config app init
myapp config set app.profile work --scope app
To add named storages later:
myapp config storage add alpha /absolute/path/to/alpha
myapp config storage add beta /absolute/path/to/beta
export MYAPP_STORAGE="alpha"
MYAPP_APPRC_TOML only relocates the named-storage index. It is not required
for the default <config-home>/<app>.apprc.toml path.
Filenames And Env Vars
| Purpose | Default |
|---|---|
| Packaged shared dotenv | .env.shared |
| App-wide dotenv | .env.apprc-app |
| Storage dotenv | .env.apprc-storage |
| Named-storage index | <app>.apprc.toml |
| Storage selector env key | derived as <APP>_STORAGE |
| Index relocation env key | derived as <APP>_APPRC_TOML |
Filename-style constructor inputs accept basenames only:
index_filenameshared_env_filenameapp_wide_env_filenamestorage_env_filename
Development
.venv/bin/ruff format .
.venv/bin/ruff check .
.venv/bin/pyright
.venv/bin/pytest
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.1.tar.gz.
File metadata
- Download URL: apprc-0.16.1.tar.gz
- Upload date:
- Size: 151.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","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 |
dac8b0b5d970477f27c43b47f5dfa290f2630c939efb0578228d7f5700af2fa9
|
|
| MD5 |
c73e88ddec205ee07a62e3b7ebe92193
|
|
| BLAKE2b-256 |
78240efe788b25b8e3692e4dde8ecbe2e34d9f916b0bf8e0cb639cf6e369e086
|
File details
Details for the file apprc-0.16.1-py3-none-any.whl.
File metadata
- Download URL: apprc-0.16.1-py3-none-any.whl
- Upload date:
- Size: 173.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","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 |
1d9482f3a82a9b703508e376354386bc9a5e6b1f27e003d47e49ca2440ce41d1
|
|
| MD5 |
4e374d10e68335ee04549b55213f7401
|
|
| BLAKE2b-256 |
7195431fc02fc5143d9c5402362683151ab3be55d6ebdfdc2d5506c4824f1e3e
|