# dotyaml
A Python library that bridges YAML configuration files and environment variables, providing the flexibility to configure applications using either approach.
## The Problem dotyaml Solves
When building applications, you often face a configuration dilemma:
**Environment variables** are great for deployment flexibility and security (keeping secrets out of code), but they can become disorganized and hard to manage. You end up with a flat list of variables like `DB_HOST`, `API_TIMEOUT`, `STRIPE_KEY`, `JWT_SECRET` with no clear structure or organization.
**YAML configuration files** provide excellent organization with nested sections, clear structure, and are easy for humans and AI coding agents to understand. However, they're not ideal for secrets management and deployment flexibility.
**dotyaml bridges this gap** by letting you have the best of both worlds:
### Structured Configuration with Automatic Environment Variable Generation
Define your configuration in organized YAML sections:
```yaml
database:
host: localhost
port: 5432
name: myapp
api:
timeout: 30
retries: 3
stripe:
publishable_key: pk_test_123
```
dotyaml automatically generates properly namespaced environment variables following a consistent pattern:
- `APP_DATABASE_HOST=localhost`
- `APP_DATABASE_PORT=5432`
- `APP_API_TIMEOUT=30`
- `APP_STRIPE_PUBLISHABLE_KEY=pk_test_123`
### Flexible Override System with Clear Precedence
The power comes from the precedence system - you can override any configuration value at multiple levels:
1. **Manual environment variables** (highest precedence) - Always win
2. **YAML configuration with environment variable interpolation**
3. **Automatic .env file loading** (lowest precedence)
This means:
- **Development**: Use `.env` files for secrets and local overrides
- **Staging/Production**: Set environment variables directly to override anything
- **Team sharing**: Commit the YAML structure to git, keep secrets in `.env` (gitignored)
- **AI/tooling friendly**: The YAML structure clearly expresses your application's configuration needs
### Example: Secrets Management Made Simple
**.env file** (gitignored, contains secrets):
```bash
DB_PASSWORD=super_secret_123
STRIPE_SECRET_KEY=sk_live_real_key
```
**config.yaml** (committed to git, safe to share):
```yaml
database:
host: "{{ DB_HOST|localhost }}"
username: admin
password: "{{ DB_PASSWORD }}" # Comes from .env
stripe:
secret_key: "{{ STRIPE_SECRET_KEY }}" # Comes from .env
webhook_endpoint: /webhooks/stripe
```
**Result**: Clean, organized configuration with secure secrets management and full deployment flexibility.
## Installation
```bash
pip install dotyaml
```
dotyaml automatically includes `python-dotenv` for `.env` file support and environment variable interpolation.
## Quick Start
Just like python-dotenv, dotyaml is designed to be simple to use. It automatically loads `.env` files and supports environment variable interpolation:
```python
from dotyaml import load_config
# Automatically loads .env file first, then processes YAML with variable interpolation
load_config('config.yaml')
# Now your app can access configuration via environment variables
import os
db_host = os.getenv('APP_DATABASE_HOST')
```
**Example with secrets management:**
**.env file** (keep secret):
```bash
DB_USERNAME=admin
DB_PASSWORD=secret123
```
**config.yaml file** (safe to commit):
```yaml
database:
host: localhost
username: "{{ DB_USERNAME }}"
password: "{{ DB_PASSWORD }}"
```
## Basic Usage
### 1. Create a YAML configuration file
**config.yaml:**
```yaml
database:
host: localhost
port: 5432
name: myapp
api:
timeout: 30
retries: 3
```
### 2. Load configuration in your Python application
```python
from dotyaml import load_config
# This will set environment variables based on your YAML structure
load_config('config.yaml', prefix='APP')
# Environment variables are now available:
# APP_DATABASE_HOST=localhost
# APP_DATABASE_PORT=5432
# APP_DATABASE_NAME=myapp
# APP_API_TIMEOUT=30
# APP_API_RETRIES=3
```
### 3. Use environment variables in your application
```python
import os
# Your application code remains simple and flexible
database_config = {
'host': os.getenv('APP_DATABASE_HOST'),
'port': int(os.getenv('APP_DATABASE_PORT')),
'name': os.getenv('APP_DATABASE_NAME')
}
```
## Alternative: Environment Variables Only
Your application works the same way even without a YAML file:
```bash
# Set environment variables directly
export APP_DATABASE_HOST=prod-db.example.com
export APP_DATABASE_PORT=5432
export APP_DATABASE_NAME=production
export APP_API_TIMEOUT=60
export APP_API_RETRIES=5
```
```python
# Your application code doesn't change
import os
database_config = {
'host': os.getenv('APP_DATABASE_HOST'),
'port': int(os.getenv('APP_DATABASE_PORT')),
'name': os.getenv('APP_DATABASE_NAME')
}
```
## Advanced Usage
### Environment Variable Precedence
Environment variables always take precedence over YAML values:
```python
# YAML file has database.host: localhost
# But environment variable is set:
os.environ['APP_DATABASE_HOST'] = 'prod-db.example.com'
load_config('config.yaml', prefix='APP')
# Result: APP_DATABASE_HOST=prod-db.example.com (env var wins)
```
### Force Override
Override existing environment variables with YAML values:
```python
load_config('config.yaml', prefix='APP', override=True)
```
### ConfigLoader for Advanced Use Cases
```python
from dotyaml import ConfigLoader
# Load configuration without setting environment variables
loader = ConfigLoader(prefix='APP')
config = loader.load_from_yaml('config.yaml') # Returns dict
# Load configuration from environment variables only
env_config = loader.load_from_env()
# Set environment variables from configuration dict
loader.set_env_vars(config)
```
### Automatic .env File Loading and Environment Variable Interpolation
dotyaml automatically loads `.env` files and supports environment variable interpolation in YAML files using Jinja-like syntax. This is perfect for managing secrets securely:
#### Basic Environment Variable Interpolation
Use `{{ VARIABLE_NAME }}` syntax in your YAML files to interpolate environment variables:
```yaml
# config.yaml
database:
host: localhost
username: "{{ DB_USERNAME }}"
password: "{{ DB_PASSWORD }}"
name: myapp
api:
key: "{{ API_SECRET_KEY }}"
timeout: 30
```
```python
from dotyaml import load_config
# Automatically loads .env file first, then processes YAML with interpolation
config = load_config('config.yaml', prefix='APP')
```
#### Using Default Values
Provide default values using the pipe syntax `{{ VARIABLE_NAME|default_value }}`:
```yaml
# config.yaml
database:
host: "{{ DB_HOST|localhost }}"
username: "{{ DB_USERNAME|dev_user }}"
password: "{{ DB_PASSWORD|dev_password }}"
port: "{{ DB_PORT|5432 }}"
```
#### Recommended Pattern: Secrets in .env, Config in YAML
**Create `.env` file for secrets** (add to `.gitignore`):
```bash
# .env - Keep this file secret and out of version control!
DB_USERNAME=production_admin
DB_PASSWORD=super_secret_password_123!
API_SECRET_KEY=sk_live_abc123def456ghi789
JWT_SECRET=jwt_signing_secret_xyz789
```
**Create YAML config file** (safe to commit to git):
```yaml
# config.yaml - Safe to commit to version control
app:
name: MyApp
debug: false
database:
host: "{{ DB_HOST|localhost }}"
port: 5432
username: "{{ DB_USERNAME }}" # Required from .env
password: "{{ DB_PASSWORD }}" # Required from .env
name: "{{ DB_NAME|myapp_production }}"
ssl: true
api:
secret_key: "{{ API_SECRET_KEY }}" # Required from .env
jwt_secret: "{{ JWT_SECRET }}" # Required from .env
timeout: 30
```
**Load in your application**:
```python
from dotyaml import load_config
# Automatically loads .env first, then interpolates variables in YAML
config = load_config('config.yaml', prefix='MYAPP')
# Your secrets are now available as environment variables:
# MYAPP_DATABASE_USERNAME=production_admin
# MYAPP_DATABASE_PASSWORD=super_secret_password_123!
# MYAPP_API_SECRET_KEY=sk_live_abc123def456ghi789
```
#### Advanced .env Integration
You can also customize .env file loading:
```python
from dotyaml import load_config
# Custom .env path
config = load_config('config.yaml', prefix='APP', dotenv_path='.env.production')
# Disable automatic .env loading
config = load_config('config.yaml', prefix='APP', load_dotenv_first=False)
# Custom .env path with ConfigLoader
from dotyaml import ConfigLoader
loader = ConfigLoader(prefix='APP', dotenv_path='.env.staging')
yaml_config = loader.load_from_yaml('config.yaml')
```
**Precedence order** (highest to lowest):
1. **Manually set environment variables** (highest precedence) - Never overridden
2. **Variables from `.env` file** (loaded automatically) - Only set if not already defined
3. **Interpolated values with defaults in YAML** - Uses existing env vars or defaults
4. **Regular YAML configuration values** (lowest precedence)
**Critical guarantee**: If you manually set any environment variable (either the final prefixed name like `APP_DATABASE_HOST` or an interpolation source like `DB_PASSWORD`), dotyaml will **never override it**. This ensures that manual configuration always takes precedence, whether set via command line, deployment scripts, or any other method.
This pattern gives you maximum flexibility and security:
- **Development**: Use `.env` for secrets and local overrides
- **Staging**: Use different `.env` files per environment
- **Production**: Use environment variables only (no `.env` file)
- **Security**: Keep secrets out of your git repository
### Data Type Handling
dotyaml automatically handles various YAML data types:
- **Strings**: Passed through as-is
- **Numbers**: Converted to string representations
- **Booleans**: Converted to `"true"`/`"false"`
- **Lists**: Converted to comma-separated strings
- **Null values**: Converted to empty strings
## License
MIT License - see [LICENSE](LICENSE) file for details.
Raw data
{
"_id": null,
"home_page": null,
"name": "dotyaml",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "yaml, environment, config, configuration, dotenv, 12factor",
"author": "dotyaml contributors",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/e2/c2/2e49f4917fb80eb20854f92096145a83113f64b02ad25b4ed15315aca72a/dotyaml-0.1.3.tar.gz",
"platform": null,
"description": "# dotyaml\n\nA Python library that bridges YAML configuration files and environment variables, providing the flexibility to configure applications using either approach.\n\n## The Problem dotyaml Solves\n\nWhen building applications, you often face a configuration dilemma:\n\n**Environment variables** are great for deployment flexibility and security (keeping secrets out of code), but they can become disorganized and hard to manage. You end up with a flat list of variables like `DB_HOST`, `API_TIMEOUT`, `STRIPE_KEY`, `JWT_SECRET` with no clear structure or organization.\n\n**YAML configuration files** provide excellent organization with nested sections, clear structure, and are easy for humans and AI coding agents to understand. However, they're not ideal for secrets management and deployment flexibility.\n\n**dotyaml bridges this gap** by letting you have the best of both worlds:\n\n### Structured Configuration with Automatic Environment Variable Generation\n\nDefine your configuration in organized YAML sections:\n\n```yaml\ndatabase:\n host: localhost\n port: 5432\n name: myapp\napi:\n timeout: 30\n retries: 3\nstripe:\n publishable_key: pk_test_123\n```\n\ndotyaml automatically generates properly namespaced environment variables following a consistent pattern:\n- `APP_DATABASE_HOST=localhost`\n- `APP_DATABASE_PORT=5432`\n- `APP_API_TIMEOUT=30`\n- `APP_STRIPE_PUBLISHABLE_KEY=pk_test_123`\n\n### Flexible Override System with Clear Precedence\n\nThe power comes from the precedence system - you can override any configuration value at multiple levels:\n\n1. **Manual environment variables** (highest precedence) - Always win\n2. **YAML configuration with environment variable interpolation** \n3. **Automatic .env file loading** (lowest precedence)\n\nThis means:\n- **Development**: Use `.env` files for secrets and local overrides\n- **Staging/Production**: Set environment variables directly to override anything\n- **Team sharing**: Commit the YAML structure to git, keep secrets in `.env` (gitignored)\n- **AI/tooling friendly**: The YAML structure clearly expresses your application's configuration needs\n\n### Example: Secrets Management Made Simple\n\n**.env file** (gitignored, contains secrets):\n```bash\nDB_PASSWORD=super_secret_123\nSTRIPE_SECRET_KEY=sk_live_real_key\n```\n\n**config.yaml** (committed to git, safe to share):\n```yaml\ndatabase:\n host: \"{{ DB_HOST|localhost }}\"\n username: admin\n password: \"{{ DB_PASSWORD }}\" # Comes from .env\nstripe:\n secret_key: \"{{ STRIPE_SECRET_KEY }}\" # Comes from .env\n webhook_endpoint: /webhooks/stripe\n```\n\n**Result**: Clean, organized configuration with secure secrets management and full deployment flexibility.\n\n## Installation\n\n```bash\npip install dotyaml\n```\n\ndotyaml automatically includes `python-dotenv` for `.env` file support and environment variable interpolation.\n\n## Quick Start\n\nJust like python-dotenv, dotyaml is designed to be simple to use. It automatically loads `.env` files and supports environment variable interpolation:\n\n```python\nfrom dotyaml import load_config\n\n# Automatically loads .env file first, then processes YAML with variable interpolation\nload_config('config.yaml')\n\n# Now your app can access configuration via environment variables\nimport os\ndb_host = os.getenv('APP_DATABASE_HOST')\n```\n\n**Example with secrets management:**\n\n**.env file** (keep secret):\n```bash\nDB_USERNAME=admin\nDB_PASSWORD=secret123\n```\n\n**config.yaml file** (safe to commit):\n```yaml\ndatabase:\n host: localhost\n username: \"{{ DB_USERNAME }}\"\n password: \"{{ DB_PASSWORD }}\"\n```\n\n## Basic Usage\n\n### 1. Create a YAML configuration file\n\n**config.yaml:**\n```yaml\ndatabase:\n host: localhost\n port: 5432\n name: myapp\napi:\n timeout: 30\n retries: 3\n```\n\n### 2. Load configuration in your Python application\n\n```python\nfrom dotyaml import load_config\n\n# This will set environment variables based on your YAML structure\nload_config('config.yaml', prefix='APP')\n\n# Environment variables are now available:\n# APP_DATABASE_HOST=localhost\n# APP_DATABASE_PORT=5432\n# APP_DATABASE_NAME=myapp\n# APP_API_TIMEOUT=30\n# APP_API_RETRIES=3\n```\n\n### 3. Use environment variables in your application\n\n```python\nimport os\n\n# Your application code remains simple and flexible\ndatabase_config = {\n 'host': os.getenv('APP_DATABASE_HOST'),\n 'port': int(os.getenv('APP_DATABASE_PORT')),\n 'name': os.getenv('APP_DATABASE_NAME')\n}\n```\n\n## Alternative: Environment Variables Only\n\nYour application works the same way even without a YAML file:\n\n```bash\n# Set environment variables directly\nexport APP_DATABASE_HOST=prod-db.example.com\nexport APP_DATABASE_PORT=5432\nexport APP_DATABASE_NAME=production\nexport APP_API_TIMEOUT=60\nexport APP_API_RETRIES=5\n```\n\n```python\n# Your application code doesn't change\nimport os\ndatabase_config = {\n 'host': os.getenv('APP_DATABASE_HOST'),\n 'port': int(os.getenv('APP_DATABASE_PORT')),\n 'name': os.getenv('APP_DATABASE_NAME')\n}\n```\n\n## Advanced Usage\n\n### Environment Variable Precedence\n\nEnvironment variables always take precedence over YAML values:\n\n```python\n# YAML file has database.host: localhost\n# But environment variable is set:\nos.environ['APP_DATABASE_HOST'] = 'prod-db.example.com'\n\nload_config('config.yaml', prefix='APP')\n# Result: APP_DATABASE_HOST=prod-db.example.com (env var wins)\n```\n\n### Force Override\n\nOverride existing environment variables with YAML values:\n\n```python\nload_config('config.yaml', prefix='APP', override=True)\n```\n\n### ConfigLoader for Advanced Use Cases\n\n```python\nfrom dotyaml import ConfigLoader\n\n# Load configuration without setting environment variables\nloader = ConfigLoader(prefix='APP')\nconfig = loader.load_from_yaml('config.yaml') # Returns dict\n\n# Load configuration from environment variables only\nenv_config = loader.load_from_env()\n\n# Set environment variables from configuration dict\nloader.set_env_vars(config)\n```\n\n### Automatic .env File Loading and Environment Variable Interpolation\n\ndotyaml automatically loads `.env` files and supports environment variable interpolation in YAML files using Jinja-like syntax. This is perfect for managing secrets securely:\n\n#### Basic Environment Variable Interpolation\n\nUse `{{ VARIABLE_NAME }}` syntax in your YAML files to interpolate environment variables:\n\n```yaml\n# config.yaml\ndatabase:\n host: localhost\n username: \"{{ DB_USERNAME }}\"\n password: \"{{ DB_PASSWORD }}\"\n name: myapp\napi:\n key: \"{{ API_SECRET_KEY }}\"\n timeout: 30\n```\n\n```python\nfrom dotyaml import load_config\n\n# Automatically loads .env file first, then processes YAML with interpolation\nconfig = load_config('config.yaml', prefix='APP')\n```\n\n#### Using Default Values\n\nProvide default values using the pipe syntax `{{ VARIABLE_NAME|default_value }}`:\n\n```yaml\n# config.yaml\ndatabase:\n host: \"{{ DB_HOST|localhost }}\"\n username: \"{{ DB_USERNAME|dev_user }}\"\n password: \"{{ DB_PASSWORD|dev_password }}\"\n port: \"{{ DB_PORT|5432 }}\"\n```\n\n#### Recommended Pattern: Secrets in .env, Config in YAML\n\n**Create `.env` file for secrets** (add to `.gitignore`):\n```bash\n# .env - Keep this file secret and out of version control!\nDB_USERNAME=production_admin\nDB_PASSWORD=super_secret_password_123!\nAPI_SECRET_KEY=sk_live_abc123def456ghi789\nJWT_SECRET=jwt_signing_secret_xyz789\n```\n\n**Create YAML config file** (safe to commit to git):\n```yaml\n# config.yaml - Safe to commit to version control\napp:\n name: MyApp\n debug: false\n\ndatabase:\n host: \"{{ DB_HOST|localhost }}\"\n port: 5432\n username: \"{{ DB_USERNAME }}\" # Required from .env\n password: \"{{ DB_PASSWORD }}\" # Required from .env\n name: \"{{ DB_NAME|myapp_production }}\"\n ssl: true\n\napi:\n secret_key: \"{{ API_SECRET_KEY }}\" # Required from .env\n jwt_secret: \"{{ JWT_SECRET }}\" # Required from .env\n timeout: 30\n```\n\n**Load in your application**:\n```python\nfrom dotyaml import load_config\n\n# Automatically loads .env first, then interpolates variables in YAML\nconfig = load_config('config.yaml', prefix='MYAPP')\n\n# Your secrets are now available as environment variables:\n# MYAPP_DATABASE_USERNAME=production_admin\n# MYAPP_DATABASE_PASSWORD=super_secret_password_123!\n# MYAPP_API_SECRET_KEY=sk_live_abc123def456ghi789\n```\n\n#### Advanced .env Integration\n\nYou can also customize .env file loading:\n\n```python\nfrom dotyaml import load_config\n\n# Custom .env path\nconfig = load_config('config.yaml', prefix='APP', dotenv_path='.env.production')\n\n# Disable automatic .env loading\nconfig = load_config('config.yaml', prefix='APP', load_dotenv_first=False)\n\n# Custom .env path with ConfigLoader\nfrom dotyaml import ConfigLoader\nloader = ConfigLoader(prefix='APP', dotenv_path='.env.staging')\nyaml_config = loader.load_from_yaml('config.yaml')\n```\n\n**Precedence order** (highest to lowest):\n1. **Manually set environment variables** (highest precedence) - Never overridden\n2. **Variables from `.env` file** (loaded automatically) - Only set if not already defined\n3. **Interpolated values with defaults in YAML** - Uses existing env vars or defaults\n4. **Regular YAML configuration values** (lowest precedence)\n\n**Critical guarantee**: If you manually set any environment variable (either the final prefixed name like `APP_DATABASE_HOST` or an interpolation source like `DB_PASSWORD`), dotyaml will **never override it**. This ensures that manual configuration always takes precedence, whether set via command line, deployment scripts, or any other method.\n\nThis pattern gives you maximum flexibility and security:\n- **Development**: Use `.env` for secrets and local overrides\n- **Staging**: Use different `.env` files per environment\n- **Production**: Use environment variables only (no `.env` file)\n- **Security**: Keep secrets out of your git repository\n\n### Data Type Handling\n\ndotyaml automatically handles various YAML data types:\n\n- **Strings**: Passed through as-is\n- **Numbers**: Converted to string representations\n- **Booleans**: Converted to `\"true\"`/`\"false\"`\n- **Lists**: Converted to comma-separated strings\n- **Null values**: Converted to empty strings\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n",
"bugtrack_url": null,
"license": null,
"summary": "Bridge YAML configuration files and environment variables for flexible app deployment",
"version": "0.1.3",
"project_urls": {
"Bug Reports": "https://github.com/AnthusAI/dotyaml/issues",
"Homepage": "https://github.com/AnthusAI/dotyaml",
"Source": "https://github.com/AnthusAI/dotyaml"
},
"split_keywords": [
"yaml",
" environment",
" config",
" configuration",
" dotenv",
" 12factor"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "d7161f9f2949b1556fd6cc69de1df370a5f26773d5df806b1ff1be1f31fd2e31",
"md5": "5fe742b555327a7bc3650ca8939dc388",
"sha256": "c764e88d4b097e8df6c350f5a64f5d4ce20ed23b1d7f2376b0e38404f414b34b"
},
"downloads": -1,
"filename": "dotyaml-0.1.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5fe742b555327a7bc3650ca8939dc388",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 9995,
"upload_time": "2025-09-16T18:29:49",
"upload_time_iso_8601": "2025-09-16T18:29:49.121015Z",
"url": "https://files.pythonhosted.org/packages/d7/16/1f9f2949b1556fd6cc69de1df370a5f26773d5df806b1ff1be1f31fd2e31/dotyaml-0.1.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "e2c22e49f4917fb80eb20854f92096145a83113f64b02ad25b4ed15315aca72a",
"md5": "9c446e6c67b44b5c9377d6043efc212d",
"sha256": "68e56e1c8cc58ad7fcff33b0d662f5f9f65c9bbcd46daf61371922fe8cbfa824"
},
"downloads": -1,
"filename": "dotyaml-0.1.3.tar.gz",
"has_sig": false,
"md5_digest": "9c446e6c67b44b5c9377d6043efc212d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 25033,
"upload_time": "2025-09-16T18:29:50",
"upload_time_iso_8601": "2025-09-16T18:29:50.228026Z",
"url": "https://files.pythonhosted.org/packages/e2/c2/2e49f4917fb80eb20854f92096145a83113f64b02ad25b4ed15315aca72a/dotyaml-0.1.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-16 18:29:50",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "AnthusAI",
"github_project": "dotyaml",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "dotyaml"
}