Metadata-Version: 2.5
Name: cognisn-konfig
Version: 0.3.0
Summary: Settings management, pluggable secrets, and run-scoped logging for Python applications.
Author: Matthew Westwood-Hill
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: cryptography>=42.0
Requires-Dist: keyring>=25.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: tomli>=2.0; python_version < '3.11'
Provides-Extra: aws
Requires-Dist: boto3>=1.34; extra == 'aws'
Provides-Extra: dev
Requires-Dist: black<25,>=24.0.0; extra == 'dev'
Requires-Dist: isort<6,>=5.13.0; extra == 'dev'
Requires-Dist: mypy<2,>=1.8.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: tomli>=2.0; extra == 'dev'
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
Description-Content-Type: text/markdown

# Konfig

[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Cognisn_konfig&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Cognisn_konfig)
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=Cognisn_konfig&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=Cognisn_konfig)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=Cognisn_konfig&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=Cognisn_konfig)
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=Cognisn_konfig&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=Cognisn_konfig)
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=Cognisn_konfig&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=Cognisn_konfig)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=Cognisn_konfig&metric=bugs)](https://sonarcloud.io/summary/new_code?id=Cognisn_konfig)
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=Cognisn_konfig&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=Cognisn_konfig)
[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=Cognisn_konfig&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=Cognisn_konfig)

Settings management, pluggable secrets, and run-scoped logging for Python applications.

Konfig provides three foundational capabilities every Python application needs, with an optional lightweight app lifecycle context manager that ties them together. It is a clean-sheet replacement for `dtPyAppFramework`.

## Features

- **Layered settings** with system/user/env/runtime precedence and persistent writes
- **Pluggable secrets** with OS keyring, AES-encrypted file, and AWS Secrets Manager backends
- **Run-scoped logging** with historical retention, structured JSON mode, and stdio-safe output
- **Platform-aware defaults** for config, data, and log directories (macOS, Linux, Windows)
- **Optional app lifecycle** via a sync/async context manager — no inheritance required
- Python 3.10+

## Installation

```bash
pip install konfig
```

For AWS Secrets Manager support:

```bash
pip install konfig[aws]
```

## Secrets

### AWS Secrets Manager (designated secret)

Point konfig at a single AWS secret that holds a JSON bundle of your secrets (the secret must
already exist):

```bash
export KONFIG_AWS_SECRETS_MANAGER=arn:aws:secretsmanager:eu-west-1:123456789012:secret:myapp/secrets-AbCdEf
```

```python
from konfig import Secrets

secrets = Secrets()               # env var selects the AWS bundle backend
api_key = secrets.get("api_key")
secrets.set("api_key", "sk-new")  # read-modify-write back to the bundle
```

Requires `pip install konfig[aws]`.

### AWS Secrets Manager settings document (`KONFIG_AWS_SETTINGS`)

Deliver an application's entire configuration as one JSON document held in a
single Secrets Manager secret — no config file or per-setting environment
variables needed in the task definition:

```bash
export KONFIG_AWS_SETTINGS=arn:aws:secretsmanager:eu-west-1:123456789012:secret:myapp/settings-AbCdEf
```

The secret's `SecretString` must be a JSON object holding the same nested
settings tree a config file would. A plain secret name is also accepted; the
region then comes from the default AWS provider chain (with an ARN it is
taken from the ARN). An equivalent constructor argument exists for
programmatic use — `Settings(aws_settings=...)` — with the environment
variable winning when both are set. Requires `pip install konfig[aws]`.

Precedence (highest to lowest):
`runtime -> env vars -> AWS settings -> user file -> system file -> defaults`
— environment variables remain the operator's immediate per-container
override, while the AWS document overrides anything baked into the image.

Behaviour:

- **Read-only.** `settings.set(...)` keeps writing to the runtime layer or
  config files exactly as before.
- **Fail fast.** A missing/unreadable secret, non-JSON payload, or
  non-object top level raises at startup rather than silently degrading to
  defaults. Error messages name the secret, never its payload.
- **Fetched once.** The document is read at construction and only re-fetched
  by `settings.reload()`; there is no background polling.
- **Composes with secrets.** Values in the document may be `secret://` URIs,
  resolved as usual by the active secrets backend.

This is independent of `KONFIG_AWS_SECRETS_MANAGER`. Pointing both at the
same secret works, but keeping configuration and secret material in separate
Secrets Manager entries is recommended so IAM can distinguish "may read
config" from "may read credentials".

### Running the LocalStack integration tests

The AWS integrations have opt-in integration tests that run against a local
[LocalStack](https://www.localstack.cloud/) container (no AWS account needed). They
auto-skip when LocalStack is not running, so they never affect the normal test run.

```bash
docker compose up -d         # start LocalStack
pip install -e ".[dev,aws]"  # boto3 + dev tools
pytest -m localstack         # run only the integration test
docker compose down          # stop LocalStack
```

## Quick Start

```python
from konfig import AppContext

with AppContext(
    name="My Application",
    version="1.0.0",
    config_file="config.yaml",
    env_prefix="MYAPP",
) as ctx:
    host = ctx.settings.get("database.host", "localhost")
    api_key = ctx.secrets.get("api_key")
    ctx.logger.info("Starting with host=%s", host)
```

For async applications:

```python
async with AppContext(name="My Server", version="2.0.0") as ctx:
    await run_server(ctx.settings)
```

### Config file format

The config file format is chosen by the `KONFIG_CONFIG_FORMAT` environment variable
(`yaml`, `json`, or `sqlite`). When unset, the format is detected from the file extension,
defaulting to YAML. Reading, updating, and creating settings work in every format.
(TOML config files are still supported by extension detection, but are read-only and
cannot be selected via `KONFIG_CONFIG_FORMAT`.)

```bash
export KONFIG_CONFIG_FORMAT=sqlite   # store settings in a SQLite database file
```

```python
from konfig import Settings

settings = Settings(config_file="config.db")
settings.set("database.host", "localhost", persist="user")  # written to SQLite
settings.set("debug", True)                                  # omit persist: in-memory only
host = settings.get("database.host")
```

Each subsystem (Settings, Secrets, LogManager) can also be used independently. See the full documentation in the [`docs/`](docs/) directory:

- [Settings Guide](docs/settings.md)
- [Secrets Guide](docs/secrets.md)
- [Logging Guide](docs/logging.md)
- [AppContext Guide](docs/app-context.md)
- [Platform Paths](docs/platform-paths.md)
- [Configuration Reference](docs/configuration-reference.md)
- [API Reference](docs/api-reference.md)

## Samples

Working examples are provided in the [`samples/`](samples/) directory:

| File | Description |
|------|-------------|
| [`basic_settings.py`](samples/basic_settings.py) | Config files, defaults, env vars, overrides |
| [`secrets_usage.py`](samples/secrets_usage.py) | Store, retrieve, and delete secrets |
| [`logging_demo.py`](samples/logging_demo.py) | Run-scoped logging with retention |
| [`app_context.py`](samples/app_context.py) | Full lifecycle with all subsystems |
| [`async_app.py`](samples/async_app.py) | Async context manager usage |
| [`custom_backend.py`](samples/custom_backend.py) | Implementing a custom SecretBackend |

## Development

```bash
pip install -e ".[dev]"
pytest
pytest --cov=konfig
mypy src/konfig
black src/ tests/
isort src/ tests/
```

## License

MIT License. See [LICENSE](LICENSE) for details.
