Generate a TOML config-file skeleton from the [config: key] annotations in doc.
Every option declaring a [config: dotted.key] becomes an entry under its table, seeded with the
option's [default: ...] (or an empty placeholder), and commented with the CLI flag and any
[env: VAR] it also reads. Options without a [config:] key are not part of the file. Returns
an empty string when the usage declares no config keys. Config keys that cannot coexist in one TOML
document (a duplicate, or a path that is a prefix of another) raise
DocoptLanguageError.
Source code in src/docopt2/_generate.py
| def generate_config_template(doc: str) -> str:
"""Generate a TOML config-file skeleton from the ``[config: key]`` annotations in ``doc``.
Every option declaring a ``[config: dotted.key]`` becomes an entry under its table, seeded with the
option's ``[default: ...]`` (or an empty placeholder), and commented with the CLI flag and any
``[env: VAR]`` it also reads. Options without a ``[config:]`` key are not part of the file. Returns
an empty string when the usage declares no config keys. Config keys that cannot coexist in one TOML
document (a duplicate, or a path that is a prefix of another) raise
[`DocoptLanguageError`][docopt2.DocoptLanguageError].
"""
single_usage_section(doc) # fail loudly on a malformed usage, like the other generators
config_options = [option for option in parse_defaults(doc) if option.config_key is not None]
_reject_colliding_config_keys([str(option.config_key) for option in config_options])
tables: dict[str, list[tuple[str, Option]]] = {}
order: list[str] = []
for option in config_options:
*prefix, leaf = str(option.config_key).split(".")
table = ".".join(prefix)
if table not in tables:
tables[table] = []
order.append(table)
tables[table].append((leaf, option))
# TOML requires root keys before any [table] header, so emit the unnamed table first.
order = ([""] if "" in tables else []) + [table for table in order if table]
blocks: list[str] = []
for table in order:
header = ["[" + ".".join(_toml_key(segment) for segment in table.split(".")) + "]"] if table else []
rows = [(f"{_toml_key(leaf)} = {_toml_value(opt.value)}", _config_comment(opt)) for leaf, opt in tables[table]]
width = max(len(entry) for entry, _ in rows)
blocks.append("\n".join([*header, *(f"{entry.ljust(width)}{comment}" for entry, comment in rows)]))
return "\n\n".join(blocks) + "\n" if blocks else ""
|