Metadata-Version: 2.4
Name: decouplet
Version: 0.2.4
Summary: Decouple config with support for secrets directory (e.g., Docker secrets)
Author-email: Kulbarakov Bakdoolot <kulbarakovbh@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://gitlab.com/mdigital-public/backend/decouplet
Project-URL: Repository, https://gitlab.com/mdigital-public/backend/decouplet
Project-URL: Documentation, https://gitlab.com/mdigital-public/backend/decouplet/-/tree/main/docs
Project-URL: Changelog, https://gitlab.com/mdigital-public/backend/decouplet/-/blob/main/CHANGELOG.md
Project-URL: Issues, https://gitlab.com/mdigital-public/backend/decouplet/-/issues
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-decouple>=3.8
Dynamic: license-file

# decouplet

A tiny wrapper around [python-decouple](https://pypi.org/project/python-decouple/) that adds first-class support for reading secrets from a directory (e.g. Docker secrets mounted at `/run/secrets/`).

Drop-in replacement for `python-decouple`'s `config` — same API, extra secrets support.

Source code: <https://gitlab.com/mdigital-public/backend/decouplet>

## Documentation

- [Documentation index](https://gitlab.com/mdigital-public/backend/decouplet/-/tree/main/docs)
- [Getting started](https://gitlab.com/mdigital-public/backend/decouplet/-/blob/main/docs/getting-started.md)
- [Configuration](https://gitlab.com/mdigital-public/backend/decouplet/-/blob/main/docs/configuration.md)
- [Docker secrets](https://gitlab.com/mdigital-public/backend/decouplet/-/blob/main/docs/guides/docker-secrets.md)
- [Migration to 0.2.x](https://gitlab.com/mdigital-public/backend/decouplet/-/blob/main/docs/migration/0.2.md)
- [Changelog](https://gitlab.com/mdigital-public/backend/decouplet/-/blob/main/CHANGELOG.md)
- [Examples](https://gitlab.com/mdigital-public/backend/decouplet/-/tree/main/examples)

## Installation

```bash
pip install decouplet
```

Install directly from the public GitLab repository:

```bash
pip install "git+https://gitlab.com/mdigital-public/backend/decouplet.git"
```

## Usage

```python
from decouplet import config

# Read a value — checked in secrets dir first, then env vars / .env or settings.ini
DATABASE_PASSWORD = config("DATABASE_PASSWORD")

# With a default
DEBUG = config("DEBUG", default="False")

# With type casting (inherited from python-decouple)
PORT = config("PORT", default=8000, cast=int)
IS_ENABLED = config("IS_ENABLED", default=False, cast=bool)
```

## Priority order

When looking up a key, `decouplet` checks sources in this order:

1. **Secrets directory** — files in `/run/secrets/` (or the path set via `SECRETS_PATH`)
2. **Environment variables**
3. **settings.ini or .env file** (standard python-decouple behaviour)
4. **Default value** (if provided)

> Secrets always win. This matches the expected behaviour when deploying with Docker Swarm or Kubernetes secrets.

## Secrets directory

Each secret is stored as a plain-text file whose **filename** (uppercased) becomes the key and whose **contents** become the value. Trailing whitespace/newlines are stripped automatically.

```
/run/secrets/
    database_password   →  key: DATABASE_PASSWORD
    api_key             →  key: API_KEY
```

### Changing the secrets path

Set the `SECRETS_PATH` environment variable to point to a different directory:

```bash
SECRETS_PATH=/my/secrets python app.py
```

Or in your `.env` file:

```
SECRETS_PATH=/my/secrets
```

Or in `settings.ini`:

```ini
[settings]
SECRETS_PATH=/my/secrets
```

If the directory does not exist, `decouplet` silently skips it and falls back to env vars / `settings.ini` / `.env`.

## Encoding

`decouplet` follows `python-decouple`'s lazy loading behavior, so you can set file encoding before the first lookup:

```python
from decouplet import config

config.encoding = "cp1251"
SECRET_KEY = config("SECRET_KEY")
```

## Docker example

See the runnable Docker Compose example in [`examples/docker-secrets-example`](examples/docker-secrets-example/).

```yaml
# docker-compose.yml
services:
  app:
    image: myapp
    secrets:
      - database_password

secrets:
  database_password:
    file: ./secrets/database_password.txt
```

```python
# app.py
from decouplet import config

DB_PASSWORD = config("DATABASE_PASSWORD")  # read from /run/secrets/database_password
```

## Requirements

- Python >= 3.9
- python-decouple >= 3.8

## Links

- Source code: <https://gitlab.com/mdigital-public/backend/decouplet>
- Documentation: <https://gitlab.com/mdigital-public/backend/decouplet/-/tree/main/docs>
- Changelog: <https://gitlab.com/mdigital-public/backend/decouplet/-/blob/main/CHANGELOG.md>
- Issues: <https://gitlab.com/mdigital-public/backend/decouplet/-/issues>
- python-decouple: <https://pypi.org/project/python-decouple/>

## License

MIT
