Configuration Documentation¶
dotenvmodel can generate documentation for your configuration classes in multiple formats. This is useful for onboarding, CI validation, and build tool integration.
The describe() Method¶
The describe() class method generates human-readable documentation showing all environment variables, their types, required status, defaults, descriptions, and validation constraints.
from dotenvmodel import DotEnvConfig, Field
class AppConfig(DotEnvConfig):
database_url: str = Field(description="PostgreSQL connection string")
port: int = Field(default=8000, ge=1, le=65535, description="Server port")
debug: bool = Field(default=False, description="Enable debug mode")
workers: int = Field(default=4, ge=1, le=16, description="Number of worker processes")
# Generate documentation
print(AppConfig.describe())
Output Formats¶
describe() supports five output formats via the output_format parameter.
ASCII table — best for terminal output and logging. This is the default.
AppConfig
=========
+--------------+------+----------+---------+------------------------------+----------------+
| ENV Variable | Type | Required | Default | Description | Constraints |
+--------------+------+----------+---------+------------------------------+----------------+
| DATABASE_URL | str | Yes | - | PostgreSQL connection string | - |
| PORT | int | No | 8000 | Server port | ge=1, le=65535 |
| DEBUG | bool | No | False | Enable debug mode | - |
| WORKERS | int | No | 4 | Number of worker processes | ge=1, le=16 |
+--------------+------+----------+---------+------------------------------+----------------+
Markdown table — perfect for README files and documentation sites.
docs = AppConfig.describe(output_format="markdown")
# Save to file
with open("CONFIG.md", "w") as f:
f.write(docs)
The output is a standard Markdown table that renders in GitHub, GitLab, and any Markdown viewer.
JSON schema — ideal for CI validation and programmatic processing.
import json
config_spec = AppConfig.describe(output_format="json")
data = json.loads(config_spec)
# Use for validation, code generation, etc.
print(data["class_name"]) # "AppConfig"
print(data["fields"][0]["env_var"]) # "DATABASE_URL"
# Get required environment variables
required_vars = [f["env_var"] for f in data["fields"] if f["required"]]
Example JSON structure:
Styled HTML table — for web documentation and internal wikis.
File Export¶
Save documentation directly to files using the output parameter. The result is both written to the file and returned.
# Save as markdown
AppConfig.describe(output_format="markdown", output="docs/config.md")
# Save as HTML
AppConfig.describe(output_format="html", output="docs/config.html")
# Save as JSON
AppConfig.describe(output_format="json", output="config-schema.json")
# Save .env.example
AppConfig.describe(output_format="dotenv", output=".env.example")
Line Endings¶
Control line endings with the line_ending parameter. This is useful for cross-platform compatibility or when generating files for a specific OS.
# Unix line endings
AppConfig.describe(output_format="markdown", line_ending="\n")
# Windows line endings
AppConfig.describe(output_format="markdown", line_ending="\r\n")
# Classic Mac line endings
AppConfig.describe(output_format="markdown", line_ending="\r")
If line_ending is None (default), the platform default (os.linesep) is used.
Generating .env.example Files¶
The generate_env_example() method is a convenience wrapper that calls describe() with output_format="dotenv". It produces a template file with type information, constraints, examples, and helpful comments.
from dotenvmodel import DotEnvConfig, Field, SecretStr
class AppConfig(DotEnvConfig):
env_prefix = "APP_"
api_key: str = Field(min_length=32, max_length=64, description="API key for external service")
port: int = Field(default=8000, ge=1, le=65535, description="Server port number")
database_password: SecretStr = Field(
default=SecretStr("change_me_in_production"),
min_length=8,
description="Database connection password",
)
allowed_hosts: list[str] = Field(
default_factory=list,
separator=";",
max_items=10,
description="Allowed hostnames for CORS",
)
# Generate and print .env.example
print(AppConfig.generate_env_example())
# Or save directly to file
AppConfig.generate_env_example(output=".env.example")
Example output:
# Configuration for AppConfig
# All variables prefixed with: APP_
# API key for external service
# Type: str | Constraints: min_length=32, max_length=64
# Example: APP_API_KEY=your_value_here
APP_API_KEY=
# Server port number
# Type: int | Constraints: ge=1, le=65535
# APP_PORT=8000
# Database connection password
# Type: SecretStr | Constraints: min_length=8
# APP_DATABASE_PASSWORD=your_secret_here
# Allowed hostnames for CORS
# Type: list[str] | Constraints: max_items=10, separator=';'
# Example: APP_ALLOWED_HOSTS=value1;value2;value3
# APP_ALLOWED_HOSTS=
The .env.example file includes:
- Type information — Shows the expected Python type
- Parsing hints — Explains how to format complex types (e.g., comma-separated values for lists)
- Constraints — Documents validation rules (min/max length, numeric ranges, etc.)
- Examples — Shows example values for required fields and empty collection defaults (a field with a real default shows it on its own commented line instead)
- Commented defaults — Optional fields are commented out with their default values
- Secret handling —
SecretStrand DSN values are masked, including inside collections andEnummembers
How default values are rendered¶
Defaults render in the format dotenvmodel itself parses, so uncommenting a default line round-trips — for joined collections, dict pairs, JSON, Enum values, and unquoted strings for non-str fields — as long as no value contains the field's separator and no dict key contains = (a value containing = round-trips fine: pairs split on the first = only). a,b parses back as ["a", "b"], but a value that itself contains a comma would split incorrectly. For data whose values may contain the delimiter, use a Json[...] field instead. Repr-form scalar defaults are display-only and do not round-trip: datetime, timedelta, Decimal, and UUID defaults render reprs like datetime.datetime(2024, 1, 1, 12, 30), 1:00:00, Decimal('19.99'), UUID('...') that fail coercion loudly when uncommented, and a Path default renders Path('/tmp/data'), which silently loads the wrong value — set those via the environment or a Json[...] field.
list,set, andtupledefaults are joined with the field'sseparator(e.g.a,bora;b);setitems are sorted so generated files are deterministic; an empty collection renders as an empty value, not[](which would parse back as["[]"])dictdefaults render askey=valuepairs, e.g.cpu=4,mem=2Json[...]fields render as JSON, e.g.{"beta": true}Enummembers render as their values, including members inside collections; members wrappingSecretStror DSN values render masked/redacted like their scalar counterparts- Collections holding sensitive members (
list[SecretStr],set[PostgresDsn],dict[str, SecretStr], …) render<secret>— the whole default is masked, never the elements; an empty collection still renders as an empty value - A
Nonedefault renders as an empty# KEY=line: env files cannot expressNone, andKEY=Nonewould fail coercion for non-str fields when uncommented (Optionalfields map an empty value back toNone) - A
default_factoryis invoked once per render and its result is rendered with the same rules — you never see a<<lambda()>>callable repr. Generation anddescribe()therefore execute the factory: side-effecting or expensive factories run at generation time - A factory that raises during generation — or a default that cannot be rendered (e.g. a non-serializable
Json[...]value) — logs a warning and renders a placeholder comment, e.g.# KEY=<<set per environment>>(never as an example value). The JSON output format emits the"<<set per environment>>"string as its documented sentinel for unrenderable defaults
Documenting Multiple Configurations¶
Use describe_configs() to document multiple config classes in a single output. Each class is shown as a separate section.
from dotenvmodel import DotEnvConfig, Field, describe_configs
class DatabaseConfig(DotEnvConfig):
env_prefix = "DB_"
host: str = Field(description="Database host")
port: int = Field(default=5432, description="Database port")
class RedisConfig(DotEnvConfig):
env_prefix = "REDIS_"
host: str = Field(description="Redis host")
port: int = Field(default=6379, description="Redis port")
# Generate documentation for all configs
all_docs = describe_configs([DatabaseConfig, RedisConfig], output_format="markdown")
print(all_docs)
# Save to file
describe_configs(
[DatabaseConfig, RedisConfig, AppConfig],
output_format="markdown",
output="docs/configuration.md",
)
Practical Use Cases¶
Developer Onboarding¶
Generate .env.example files automatically so new developers know exactly what to configure:
# Generate .env.example with helpful comments and type information
AppConfig.generate_env_example(output=".env.example")
# Or combine multiple configs
from dotenvmodel import describe_configs
with open(".env.example", "w") as f:
f.write("# Application Configuration\n\n")
f.write("# Copy this file to .env and fill in the values\n\n")
for config_cls in [AppConfig, DatabaseConfig, RedisConfig]:
f.write(config_cls.generate_env_example())
f.write("\n\n")
CI Configuration Validation¶
Use the JSON output to validate that all required environment variables are set before deployment:
import json
import os
# Get required environment variables from config schema
spec = json.loads(AppConfig.describe(output_format="json"))
required_vars = [f["env_var"] for f in spec["fields"] if f["required"]]
# Validate all required vars are set
missing = [var for var in required_vars if var not in os.environ]
if missing:
print(f"ERROR: Missing required environment variables: {', '.join(missing)}")
exit(1)
Build Tool Integration¶
Generate documentation as part of your build process:
# build_docs.py - Run during build process
from your_app.config import AppConfig, DatabaseConfig
# Generate .env.example for repository
AppConfig.generate_env_example(output=".env.example")
# Generate markdown docs
AppConfig.describe(output_format="markdown", output="docs/CONFIG.md")
# Generate HTML for internal wiki
AppConfig.describe(output_format="html", output="docs/config.html")
print("Configuration documentation generated")
Display Configuration Reference in Development¶
Show configuration details when running in development mode:
import os
# Display configuration reference in development mode
if os.getenv("ENV") == "dev":
print("\n" + "=" * 80)
print("CONFIGURATION REFERENCE")
print("=" * 80)
print(AppConfig.describe())
print("=" * 80 + "\n")
See Also¶
- Describe API Reference —
describe_single(),describe_configs(),generate_env_example() - DotEnvConfig API Reference —
describe()andgenerate_env_example()class methods - Field Definitions —
descriptionparameter for documenting fields - Environment Prefixes — Prefixes are reflected in documentation output