A command line tool for generating Markdown documentation and .env files from pydantic BaseSettings.
MIT License
The same way you are able to generate OpenAPI documentation from pydantic.BaseModel
, settings-doc
allows you to generate documentation from pydantic_settings.BaseSettings
.
It is powered by the Jinja2 templating engine and Click framework. If you don't like the built-in templates, you can easily modify them or write completely custom ones. All attributes of the BaseSettings
models are exposed to the templates.
pip install settings-doc
See settings-doc --help
for all options.
Let's assume the following BaseSettings
in src/settings.py
of a project:
from pydantic_settings import BaseSettings
class AppSettings(BaseSettings):
logging_level: str
You can generate a Markdown documentation into stdout with:
settings-doc generate --class src.settings.AppSettings --output-format markdown
Which will output:
# `LOGGING_LEVEL`
**Required**
Similarly, you can generate a .env
file for local development with:
settings-doc generate --class src.settings.AppSettings --output-format dotenv
Which will output:
LOGGING_LEVEL=
If you have a module with a single settings class or want to load multiple classes at once as a source, you can also use the --module
option. The following example works exactly like the one above and will use the AppSettings
class automatically.
settings-doc generate --module src.settings --output-format dotenv
If multiple classes contain a field with the same name, all instances will appear in the output.
You can add any extra field parameters to the settings. By default, settings-doc
will utilise the default value, whether the parameter is required or optional, description, example value, and list of possible values:
from pydantic_settings import BaseSettings, Field
class AppSettings(BaseSettings):
logging_level: str = Field(
"WARNING",
description="Log level.",
examples=["WARNING"],
possible_values=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
)
Which will generate the following markdown:
# `LOGGING_LEVEL`
*Optional*, default value: `WARNING`
Log level.
## Examples
`WARNING`
## Possible values
`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
or .env
file:
# Log level.
# Possible values:
# `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
# LOGGING_LEVEL=WARNING
You can find even more complex usage of settings-doc
in one of my other projects.
It is possible to generate documentation into an existing document. To fit with the heading structure, you can adjust the heading levels with --heading-offset
. Additionally, you can specify the location where to generate the documentation with two marks set by --between <START MARK> <END MARK>
.
Let's assume your README.md
looks like this:
# My app
This app is distributes as a docker image and configurable via environment variables. See the list below.
# Environment variables
<!-- generated env. vars. start -->
<!-- generated env. vars. end -->
When you run:
settings-doc generate \
--class src.settings.AppSettings \
--output-format markdown \
--update README.md \
--between "<!-- generated env. vars. start -->" "<!-- generated env. vars. end -->" \
--heading-offset 1
the updated README.md
will get only the specified location overwritten:
# My app
This app is distributes as a docker image and configurable via environment variables. See the list below.
# Environment variables
<!-- generated env. vars. start -->
## `LOGGING_LEVEL`
*Optional*, default value: `WARNING`
Log level.
### Examples
`WARNING`
### Possible values
`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
<!-- generated env. vars. end -->
The settings_doc.render()
function can be used to render the documentation in code. It returns a string with the rendered documentation. Using the Minimal example from the command line usage, the code usage is as follows:
from settings_doc import render, OutputFormat
print(
render(
class_name="AppSettings",
module="src.settings",
output_format=OutputFormat.MARKDOWN,
)
)
settings-doc
comes with a few built-in templates. You can override them or write completely new ones.
To just modify the existing ones:
mkdir custom_templates
settings-doc templates --copy-to custom_templates
custom_templates
to suit your needs. You can keep only the modified ones as settings-doc
always falls back to the built-in ones.settings-doc generate \
--class src.settings.AppSettings \
--output-format dotenv \
--templates custom_templates
To create new ones, create a folder and then a Jinja2 template with a file names <OUTPUT_FORMAT>.jinja
. Then simply reference both in the command line options:
mkdir custom_templates
echo "{{ field.description }}" > custom_templates/only_descriptions.jinja
settings-doc generate \
--class src.settings.AppSettings \
--output-format only_descriptions \
--templates custom_templates
By default, there are several variables available in all templates:
heading_offset
- the value of the --heading-offset
option. Defaults to 0
.fields
is a list of str
/ FieldInfo
tuples. The string is the name of the settings attribute and the values come from BaseSettings.model_fields.values()
. In other words, a list of individual settings fields and their names. If multiple classes are used to generate the documentation, FieldInfo
s from all classes are collected into fields
. The information about original classes is not retained.classes
- a dictionary, where keys are the BaseSettings
sub-classes and values are lists of extracted FieldInfo
s of that class. This can be used for example to split individual classes into sections.Extra parameters unknown to pydantic can be stored as a dict in the json_schema_extra
attribute.
To access information from the BaseSettings
classes, use the classes
variable in the templates:
{% for cls, fields in classes.items() %}
# {{ cls.__name__ }}
{% endfor %}
It's possible to use settings-doc
as a pre-commit hook to keep your documentation up to date. There is one hook id
per output format:
settings-doc-markdown
settings-doc-dotenv
There are two caveats:
--output-format
) in the args
section.additional_dependencies
, specifying each package, that is imported inimport yaml
inExample .pre-commit-config.yaml
section provided below:
- repo: https://github.com/radeklat/settings-doc
rev: '3.0.0'
hooks:
- id: settings-doc-markdown
args:
- '--module'
- 'src.settings'
- '--update'
- 'README.md'
- '--between'
- "<!-- generated env. vars. start -->"
- "<!-- generated env. vars. end -->"
- '--heading-offset'
- '1'
additional_dependencies:
- "pyyaml>=5.3.1"
You can use the same hook to check if the documentation is up-to-date in CI:
pip install pre-commit
pre-commit run --all-files settings-doc-markdown # or other settings-doc-<output-format>
Consider caching the ~/.cache/pre-commit
environment cache for faster subsequent runs.
--output-format
: markdown, dotenv--update
, optionally between two given string marks with --between
. Useful for keeping documentation up to date.--templates
.--heading-offset
to fit into existing documentation.<VALUE>: <DESCRIPTION>
if example values are tuples of 1-2 items.