Configuration files¶
The structure of the configuration file is derived from the CLI’s parameters and their types. You never write a data structure to mirror the CLI.
Tip
After loading, the resolved file path, the full parsed document, and (when a config_schema is set) the typed app section are exposed on ctx.meta as CONF_SOURCE, CONF_FULL, and TOOL_CONFIG. With cascade=True, CONF_SOURCES additionally lists every file that was loaded. See the available keys table to read them from your own callbacks.
Resolving a configuration file¶
Before any value is read, Click Extra decides which file, if any, provides the configuration. An explicit --config (or its environment variable or interactive prompt) wins outright. Otherwise autodiscovery applies: pyproject.toml is searched from the current directory up to the VCS root, then the app-dir search pattern takes over. The first file that parses to a non-empty mapping is used, with no merging across files.
flowchart TD
start(["@config_option resolves a pattern"]) --> nc{"autodiscovery disabled?"}
nc -->|yes| skip["Skip loading, use bare defaults"]
nc -->|no| exp{"--config, env or prompt set?"}
exp -->|"no, auto-discover"| pyp{"pyproject.toml format enabled?"}
pyp -->|yes| cwd{"tool.cli table in a pyproject.toml, CWD up to VCS root?"}
cwd -->|yes| usepyp["Use that tool.cli section"]
cwd -->|no| search["Search files matching the pattern, try formats in order"]
pyp -->|no| search
exp -->|yes| search
search --> parse{"a file parses to a non-empty config?"}
parse -->|yes| win["First match wins, no merging"]
parse -->|"no, explicit"| fail["Exit with code 2"]
parse -->|"no, auto-discover"| defaults["Use bare defaults"]
Once a file is selected, its values feed into the precedence chain below: environment variables, CLI parameters, and interactive prompts all override what the file provides.
Standalone option¶
The @config_option decorator provided by Click Extra can be used as-is with vanilla Click:
from click import group, option, echo
from click_extra import config_option
@group(context_settings={"show_default": True})
@option("--dummy-flag/--no-flag")
@option("--my-list", multiple=True)
@config_option
def my_cli(dummy_flag, my_list):
echo(f"dummy_flag is {dummy_flag!r}")
echo(f"my_list is {my_list!r}")
@my_cli.command
@option("--int-param", type=int, default=10)
def subcommand(int_param):
echo(f"int_parameter is {int_param!r}")
The code above is saved in a file named my_cli.py. It produces the following help screen:
$ my-cli --help
Usage: my-cli [OPTIONS] COMMAND [ARGS]...
Options:
--dummy-flag / --no-flag [default: no-flag]
--my-list TEXT
--config LOCATION Location of the configuration file. Supports local
path with glob patterns or remote URL. [default:
~/.config/my-cli/]
--help Show this message and exit.
Commands:
subcommand
The help screen names the default location of the configuration file ([default: ~/.config/my-cli/]). This improves discoverability, and makes sysadmins happy, especially those not familiar with your CLI. The files searched in that folder depend on the formats you enabled.
A bare call returns:
$ my-cli subcommand
dummy_flag is False
my_list is ()
int_parameter is 10
A TOML file in the application folder changes the CLI’s defaults. Here is what ~/.config/my-cli/config.toml contains:
~/.config/my-cli/config.toml¶# My default configuration file.
top_level_param = "is_ignored"
[my-cli]
extra_value = "is ignored too"
dummy_flag = true # New boolean default.
my_list = ["item 1", "item #2", "Very Last Item!"]
[garbage]
# An empty random section that will be skipped.
[my-cli.subcommand]
int_param = 3
random_stuff = "will be ignored"
In the file above, note:
The default configuration base path, which is OS-dependent (the
~/.config/my-cli/path here is for Linux).The app’s folder (
/my-cli/), built from the script’s name (my_cli.py).The top-level config section (
[my-cli]), based on the CLI’s group ID (def my_cli()).The extra comments, sections and values, all silently ignored.
The configuration file is read and changes the defaults:
$ my-cli subcommand
dummy_flag is True
my_list is ('item 1', 'item #2', 'Very Last Item!')
int_parameter is 3
Key spelling¶
Configuration keys address CLI parameters by name, in either of two spellings:
kebab-case is the canonical presentation: it matches the spelling of the CLI flags and the convention of TOML and YAML files. It is what
--export-configemits.snake_case is the parameter’s internal ID, which Click derives from the flag by replacing hyphens with underscores: the
--dummy-flagoption is thedummy_flagparameter. This ID is what--paramsreports, and what roots the auto-generated environment variable (CLI_DUMMY_FLAG), since neither Python identifiers nor environment variables can carry dashes.
Both spellings resolve to the same parameter: dummy-flag and dummy_flag both set --dummy-flag. When the two coexist in a file, the last one in file order wins and a warning names both.
Case does not have to match either. Click folds case when it derives a parameter name from a flag, so --Dummy-Flag would also be the dummy_flag parameter, and a key spelled Dummy-Flag or DUMMY_FLAG reaches it too.
Caution
Folding is how the key is found, never how the parameter is named. Click takes a third positional declaration verbatim, so a parameter declared @option("--flag", "Dummy_Flag") really is named Dummy_Flag, and its config key keeps that case. A key is matched against the names a CLI declares, so a CLI that declares both dummy_flag and Dummy_Flag leaves DUMMY_FLAG addressing neither: nothing tells the two apart, and the key is skipped with a warning.
Note
Click also accepts snake_case flags: --my_option is legal and derives the same my_option parameter ID as --my-option would. For such a CLI the canonical config key is still the kebab-cased my-option, which loads back to the same parameter.
Decoupling the flag from the configuration key¶
Click’s third positional declaration names the parameter explicitly, decoupling it from the flags. This is handy for repeatable options, where the flag names one occurrence but the configuration key holds the whole collection: keep the flag singular and pluralize the parameter, so the config key, the environment variable and the callback argument all read as the list they are.
from click_extra import command, echo, option
@command
@option("--hash-header", "hash_headers", multiple=True)
def scanner(hash_headers):
echo(f"headers = {hash_headers!r}")
The --hash-header flag is repeated once per value:
$ scanner --hash-header Date --hash-header From
headers = ('Date', 'From')
While the configuration key, shown here by exporting the values just set, is the plural hash-headers list:
$ scanner --hash-header Date --hash-header From --export-config toml
[scanner]
hash-headers = ["Date", "From"]
time = false
accessible = false
color = "auto"
no-color = false
progress = true
theme = "dark"
table-format = "rounded-outline"
verbosity = "WARNING"
verbose = 0
quiet = 0
debug = false
tree = false
man = false
# help-format =
The environment variable follows the parameter ID too, so a single SCANNER_HASH_HEADERS value feeds the whole list.
Dotted keys¶
Configuration files support dotted keys as a shorthand for nested structures. Instead of writing:
[my-cli.subcommand]
int_param = 3
You can write:
[my-cli]
"subcommand.int_param" = 3
Both forms are equivalent. You can also freely mix them in the same file:
{
"my-cli": {
"dummy_flag": true,
"subcommand.int_param": 3,
"subcommand": {
"other_param": "value"
}
}
}
Dotted keys are expanded into nested dicts and deep-merged before the configuration is applied. This works across all supported formats, and at any nesting depth (for example, "subcommand.nested.option" expands to three levels).
Hint
This is especially handy in formats like JSON that have no native section syntax, letting you keep a flat structure when the nesting would be excessive.
Merge rules¶
When dotted keys and nested structures target the same leaf, the last one in file order wins:
{
"my-cli": {
"subcommand": {"int_param": 3},
"subcommand.int_param": 77
}
}
Here int_param resolves to 77 because the dotted key appears after the nested one.
Conflicts¶
A conflict occurs when the same key is used as both a scalar and a namespace. For example:
{
"my-cli": {
"subcommand": "some_value",
"subcommand.int_param": 3
}
}
Here subcommand is a plain string, but subcommand.int_param requires it to be a dict. By default, Click Extra logs a warning and the last value wins: in this case, subcommand becomes {"int_param": 3}, silently dropping "some_value".
In strict mode, conflicts and invalid dotted keys raise a ValueError instead of being silently resolved.
The same conflict detection applies at deeper levels:
{
"my-cli": {
"subcommand.int_param.nested": 1,
"subcommand.int_param": 2
}
}
Here int_param is set to both {"nested": 1} (via the first key) and 2 (via the second). A warning is logged and int_param resolves to 2.
Note
Most formats prevent these conflicts at parse time (TOML rejects a key used as both a scalar and a table, YAML forbids duplicate keys), so in practice this mainly affects JSON.
Invalid dotted keys¶
Dotted keys with empty segments (leading, trailing, or consecutive dots) are skipped with a warning:
{
"my-cli": {
".option": 1,
"option.": 2,
"sub..option": 3
}
}
All three keys above are ignored. Use --verbosity WARNING or higher to see the warnings. In strict mode, they raise a ValueError.
Precedence¶
The loader fetches values in the following precedence order:
flowchart TD
P["Interactive prompt"] -->|unset| C["CLI parameters"]
C -->|unset| E["Environment variables"]
E -->|unset| F["Configuration file"]
F -->|unset| D["Defaults"]
Each parameter takes the first value set in that chain.
Configuration file values are loaded into Click’s default_map, so they are reported as DEFAULT_MAP and sit below environment variables in the hierarchy.
Inline parameters take priority over the file’s defaults:
$ my-cli subcommand --int-param 555
dummy_flag is True
my_list is ('item 1', 'item #2', 'Very Last Item!')
int_parameter is 555
Get configuration values¶
The resolved values are merged into the context’s default_map. Only values matching a CLI parameter are kept and passed as defaults. All others are silently ignored.
The full configuration stays accessible in the context’s meta attribute:
from click_extra import option, echo, pass_context, command, config_option
@command
@option("--int-param", type=int, default=10)
@config_option
@pass_context
def my_cli(ctx, int_param):
echo(f"Configuration location: {ctx.meta['click_extra.conf_source']}")
echo(f"Full configuration: {ctx.meta['click_extra.conf_full']}")
echo(f"Default values: {ctx.default_map}")
echo(f"int_param is {int_param!r}")
./conf.toml¶[my-cli]
int_param = 3
random_stuff = "will be ignored"
[garbage]
dummy_flag = true
$ my-cli --config ./conf.toml --int-param 999
Load configuration matching ./conf.toml
Configuration location: /home/me/conf.toml
Full configuration: {'my-cli': {'int_param': 3, 'random_stuff': 'will be ignored'}, 'garbage': {'dummy_flag': True}}
Default values: {'int_param': 3}
int_parameter is 999
Hint
Variables in meta are presented in their original Python type:
click_extra.conf_sourceis either a normalizedPathorURLobjectclick_extra.conf_fullis adictwhose values are eitherstror richer types, depending on the capabilities of each format
Exporting the configuration¶
The @export_config_option decorator adds a --export-config FORMAT option that resolves the CLI’s current configuration and writes it to <stdout> as a ready-to-use configuration file, then exits. It is part of the default options of every @command and @group, so click-extra CLIs ship with it out of the box.
The values are resolved through the usual precedence chain: command-line parameters override environment variables, which override an autodiscovered configuration file, which overrides the defaults. So combining --export-config with other options or environment variables captures them in the generated configuration, which makes it a convenient way to freeze the current invocation into a file or to produce a starting-point template.
from click_extra import command, echo, option
@command
@option("--city", default="Lisbon")
@option("--temperature", type=int, default=18)
@option("--tags", multiple=True, default=("sunny",))
def weather(city, temperature, tags):
echo(f"{city}: {temperature}C {tags!r}")
A bare export renders every configurable parameter, including click-extra’s own built-in options:
$ weather --export-config toml
[weather]
city = "Lisbon"
temperature = 18
tags = ["sunny"]
time = false
accessible = false
color = "auto"
no-color = false
progress = true
theme = "dark"
table-format = "rounded-outline"
verbosity = "WARNING"
verbose = 0
quiet = 0
debug = false
tree = false
man = false
# help-format =
Any value set on the command line (or via an environment variable) is reflected in the export, so the output can be saved straight into a configuration file:
$ weather --city Oslo --temperature 4 --export-config toml
[weather]
city = "Oslo"
temperature = 4
tags = ["sunny"]
time = false
accessible = false
color = "auto"
no-color = false
progress = true
theme = "dark"
table-format = "rounded-outline"
verbosity = "WARNING"
verbose = 0
quiet = 0
debug = false
tree = false
man = false
# help-format =
Redirect the output to your configuration file to persist it:
$ weather --city Oslo --export-config toml > ~/.config/weather/config.toml
The accepted formats are the ones click-extra can serialize: toml, yaml, json, json5, jsonc, hjson, xml and plist. ini, sqlite, argfile and pyproject.toml have no serializer and cannot be exported. A format whose optional dependency is missing exits with code 1 and an install hint.
Exported keys use the canonical kebab-case spelling (see Key spelling), so the generated file reads like the CLI flags it mirrors.
Parameters without a value are exported too, so the generated file names every key a configuration file can set. Multi-value parameters read as empty lists, and unset scalars render as null, except in TOML which has no null type and comments them out:
from click_extra import command, echo, option
@command
@option("--regexp")
@option("--tags", multiple=True)
def filters(regexp, tags):
echo(f"{regexp!r} {tags!r}")
$ filters --export-config toml
[filters]
# regexp =
tags = []
time = false
accessible = false
color = "auto"
no-color = false
progress = true
theme = "dark"
table-format = "rounded-outline"
verbosity = "WARNING"
verbose = 0
quiet = 0
debug = false
tree = false
man = false
# help-format =
If a configuration file is discovered or passed via --config, its values are loaded before the export renders, so the output reflects the full precedence chain regardless of the order of the flags on the command line. The same guarantee applies to --params.
Note
--export-config is itself excluded from the export, like the other introspection options (--help, --version, --params, --validate-config). It requires a sibling @config_option decorator to be present on the same command.
Excluding parameters¶
The excluded_params argument blocks listed CLI options from being loaded from configuration.
It defaults to the value of DEFAULT_EXCLUDED_PARAMS, plus the CLI’s --help option, resolved at runtime.
Set your own blocklist with the excluded_params argument:
from click import command, option, echo
from click_extra import config_option
@command
@option("--int-param", type=int, default=10)
@config_option(excluded_params=["my-cli.non_configurable_option", "my-cli.dangerous_param"])
def my_cli(int_param):
echo(f"int_parameter is {int_param!r}")
Hint
Provide the fully-qualified ID of the option to block: the dot-separated ID prefixed by the CLI name. This reaches options at any level, including subcommands.
To discover options and their IDs, run your CLI with the --params option.
On the default @command and @group decorators, the excluded_params keyword extends the blocklist without replacing the whole default parameter list. Unlike the option-level argument above, it is additive: the built-in exclusions (--config, --version, --help, …) are preserved and your IDs are unioned into them.
from click_extra import command
@command(excluded_params=["my-cli.dangerous_param"])
def my_cli(): ...
Under strict mode, a blocked parameter found in a configuration file is refused with a dedicated message naming it as not allowed, rather than unknown.
Including parameters¶
The included_params argument is the inverse of excluded_params: only the listed parameters will be loaded from the configuration file. All other parameters found in the configuration will be ignored.
from click import command, option, echo
from click_extra import config_option
@command
@option("--flag-a/--no-flag-a")
@option("--flag-b/--no-flag-b")
@config_option(included_params=("my-cli.flag_a",))
def my_cli(flag_a, flag_b):
echo(f"flag_a={flag_a!r}")
echo(f"flag_b={flag_b!r}")
In the example above, only flag_a will be loaded from configuration. flag_b will keep its CLI default even if it is present in the configuration file.
Caution
included_params and excluded_params are mutually exclusive. Providing both will raise a ValueError.
Hint
Like excluded_params, this takes fully-qualified option IDs. Run your CLI with the --params option to discover them.
Schema-only configuration¶
When using config_schema for typed configuration access, your config keys typically don’t correspond to CLI parameters: they’re custom fields consumed via get_tool_config(). In that case, passing them through merge_default_map is unnecessary and can cause collisions if a config key happens to share a name with a subcommand.
Set included_params=() (empty tuple) to disable merge_default_map entirely. All configuration access goes through the schema:
from dataclasses import dataclass
from click_extra import group, pass_context
from click_extra.config import get_tool_config
@dataclass
class AppConfig:
setup_guide: bool = True
sync_interval: int = 60
@group(config_schema=AppConfig, schema_strict=True, included_params=())
@pass_context
def my_app(ctx):
config = get_tool_config(ctx)
# config is always an AppConfig instance, never None
Note
included_params=() is different from included_params=None. None means “not configured, use the default behavior” (which applies excluded_params). () means “the allowlist is explicitly empty: merge nothing into default_map.”
Disabling autodiscovery¶
By default, @config_option automatically searches for configuration files in the default application folder. If you want to disable this autodiscovery and only load a configuration file when the user explicitly passes --config <path>, use the NO_CONFIG sentinel as the default:
from click import group, option, echo
from click_extra import config_option, NO_CONFIG
@group(context_settings={"show_default": True})
@option("--dummy-flag/--no-flag")
@config_option(default=NO_CONFIG)
def my_cli(dummy_flag):
echo(f"dummy_flag is {dummy_flag!r}")
With this setup:
The
--helpoutput shows[default: disabled]instead of a filesystem path.Running the CLI without
--configproduces no configuration-related output on stderr.Users can still explicitly pass
--config <path>to load a specific configuration file.The
--no-configflag (if added via@no_config_option) still prints the “Skip configuration file loading altogether.” message when used explicitly.
This is useful for CLIs where configuration files are opt-in rather than opt-out, or when you want to avoid side effects from automatically discovered configuration files during development or testing.
Default subcommands¶
You can specify which subcommands run by default when a group is invoked without any explicit subcommands on the CLI. This is done via the _default_subcommands reserved configuration key.
Given this CLI:
from click_extra import echo, group, option
@group
def my_cli():
pass
@my_cli.command()
@option("--path", default="/tmp")
def backup(path):
echo(f"Backing up {path}")
@my_cli.command()
def sync():
echo("Syncing")
And this TOML configuration:
[my-cli]
_default_subcommands = ["backup"]
[my-cli.backup]
path = "/home"
Running my-cli alone will automatically invoke the backup subcommand:
$ my-cli --config /tmp/tmpsc3nv2df/my-cli.toml
Load configuration matching /tmp/tmpsc3nv2df/my-cli.toml
Backing up /home
Chained commands¶
For groups created with chain=True, you can list multiple default subcommands. They run in the order specified. The rest of this section builds on a chained variant of the CLI above, with a debug subcommand to prepend later:
from click_extra import echo, group, option
@group(chain=True)
def my_cli():
pass
@my_cli.command()
@option("--path", default="/tmp")
def backup(path):
echo(f"Backing up {path}")
@my_cli.command()
def sync():
echo("Syncing")
@my_cli.command()
def debug():
echo("Debug mode activated")
[my-cli]
_default_subcommands = ["backup", "sync"]
$ my-cli --config /tmp/tmp_iqzgfgq/my-cli.toml
Load configuration matching /tmp/tmp_iqzgfgq/my-cli.toml
Backing up /home
Syncing
Note
Non-chained groups only accept a single default subcommand. Listing more than one will produce an error.
CLI precedence¶
If the user names subcommands explicitly on the command line, the _default_subcommands configuration is ignored:
$ my-cli --config /tmp/tmpe7iyhce7/my-cli.toml sync
Load configuration matching /tmp/tmpe7iyhce7/my-cli.toml
Syncing
Prepend subcommands¶
The _prepend_subcommands key always prepends subcommands to every invocation, regardless of whether CLI subcommands are provided. This is useful for always injecting a subcommand (like debug) on a dev machine.
Important
_prepend_subcommands only works with chain=True groups. Non-chained groups resolve exactly one subcommand, so prepending would break the user’s intended command.
[my-cli]
_prepend_subcommands = ["debug"]
Running my-cli sync effectively becomes my-cli debug sync:
$ my-cli --config /tmp/tmpyr5_ldjd/my-cli.toml sync
Load configuration matching /tmp/tmpyr5_ldjd/my-cli.toml
Debug mode activated
Syncing
_default_subcommands with _prepend_subcommands¶
When both keys are set and no CLI subcommands are given, _default_subcommands fires first, then _prepend_subcommands is prepended. The result is [*prepend, *defaults]:
[my-cli]
_default_subcommands = ["sync"]
_prepend_subcommands = ["debug"]
$ my-cli --config /tmp/tmpvdl1_0r6/my-cli.toml
Load configuration matching /tmp/tmpvdl1_0r6/my-cli.toml
Debug mode activated
Syncing
When CLI subcommands are given explicitly, _default_subcommands is ignored but _prepend_subcommands still applies:
$ my-cli --config /tmp/tmpm02ljq7s/my-cli.toml backup
Load configuration matching /tmp/tmpm02ljq7s/my-cli.toml
Debug mode activated
Backing up /tmp
Fallback sections¶
When a CLI tool is renamed, existing configuration files may still use the old section name. The fallback_sections parameter lets you accept legacy names with a deprecation warning:
from dataclasses import dataclass
from click_extra import echo, group, pass_context
from click_extra.config import get_tool_config
@dataclass
class ToolConfig:
value: str = "default"
@group(
config_schema=ToolConfig,
fallback_sections=("old-tool-name", "even-older-name"),
)
@pass_context
def new_tool(ctx):
"""A tool that was renamed."""
config = get_tool_config(ctx)
if config is not None:
echo(f"value: {config.value}")
@new_tool.command()
def run():
"""Run the tool."""
echo("done")
With the following TOML:
[old-tool-name]
value = "from-legacy"
The CLI loads the [old-tool-name] section and logs a deprecation warning to stderr:
Config section [old-tool-name] is deprecated, migrate to [new-tool].
If both [new-tool] and [old-tool-name] exist, the current name always wins, and a warning is emitted about the leftover legacy section.
$ new-tool --help
Usage: new-tool [OPTIONS] COMMAND [ARGS]...
A tool that was renamed.
Options:
-h, --help Show this message and exit.
Configuration options:
--config LOCATION Location of the configuration file. Supports
local path with glob patterns or remote URL.
[default: ~/.config/new-tool/]
--no-config Ignore all configuration files and only use
command line parameters and environment
variables.
--validate-config LOCATION Validate the configuration file and exit.
--export-config FORMAT Export the configuration in the selected format
to <stdout>, then exit.
Output options:
--accessible Accessibility mode: disable colors and render
tables in a borderless, screen-reader-friendly
format.
--color [auto|always|never] Colorize the output. A bare --color is the same
as --color=always. [default: auto]
--no-color Disable colorization (alias of --color=never).
--progress / --no-progress Show progress indicators during long operations.
Disabled for non-interactive output (pipes, dumb
terminals, CI) and by --accessible. [default:
progress]
--theme [auto|dark|dracula|light|manpage|monokai|nord|solarized-dark]
Color theme used for help screens. [default:
dark]
--table-format FORMAT Rendering style of tables. [default: rounded-
outline]
Logging options:
--verbosity LEVEL Either CRITICAL, ERROR, WARNING, INFO, DEBUG.
[default: WARNING]
-v, --verbose Increase the default WARNING verbosity by one
level for each additional repetition of the
option. [default: 0]
-q, --quiet Decrease the default WARNING verbosity by one
level for each additional repetition of the
option. [default: 0]
--debug Shorthand for --verbosity DEBUG.
Introspection options:
--time / --no-time Measure and print elapsed execution time.
[default: no-time]
--params Show all CLI parameters, their provenance,
defaults and value, then exit.
--tree Show the tree of nested subcommands and exit.
--man Read the command's manual page and exit.
--help-format [carapace|json|json-full|man|markdown|markdown-full]
Render the command in the given format and exit.
--version Show the version and exit.
Commands:
help Show help for a command.
run Run the tool.
This works identically across all configuration formats (TOML, YAML, JSON, INI, etc.), since the section lookup operates on the normalized dict structure after parsing.
click_extra.config API¶
Click Extra’s own built-in configuration schema and validators.
These are concrete instances of the configuration machinery, kept apart from
the reusable engine in schema and the option classes
in option:
the dataclasses describing click-extra’s own
[tool.click-extra]section (ClickExtraConfigand itstest-suiteandprebakesub-tables);_builtin_config_validators(), the validators click-extra registers on everyConfigOption.
A downstream project defines its own equivalent of this module; click-extra just happens to ship one, built on the same generic engine.
- click_extra.config.builtin.THEMES_CONFIG_KEY: str = 'themes'
Sub-key under
[tool.<cli>]where user-defined themes live in config.Used by
ConfigOptionto find[tool.<cli>.themes.<name>]tables, build them viaHelpTheme.from_dict, and stash the result onctx.meta[click_extra.context.THEME_OVERRIDES]. The constant is the single source of truth shared by_builtin_config_validators,ConfigOption._apply_theme_overrides, andclick_extra.theme.themes_from_config().
- class click_extra.config.builtin.TestSuiteConfig(file='./tests/cli-test-suite.toml', cases=<factory>, timeout=None)[source]
Bases:
objectConfig schema for a project’s test suite, read from
[tool.<cli>.test-suite].The
test-suiteCLI command resolves its cases from this config when no suite is given on the command line. Map it onto an app’s config section with a field carryingmetadata={CONFIG_PATH_METADATA_KEY: "test-suite"}.- file: str = './tests/cli-test-suite.toml'
Path to a test suite file, resolved relative to the project root.
Its format is detected from the extension; the default is TOML, which (like JSON) parses with no optional dependency, unlike YAML and the others.
- cases: list[dict]
Test cases written natively in the config format, an alternative to a
filesuite, taking precedence over it when both are set.Each entry is a mapping of
CLITestCasedirective names, equivalent to one item of a suite list. In TOML this reads as a[[tool.<cli>.test-suite.cases]]array of tables. Declared as an extension point so the configuration engine passes the raw mappings through unprocessed; thetest-suitecommand turns them intoCLITestCaseinstances.
- class click_extra.config.builtin.PrebakeConfig(module=None)[source]
Bases:
objectConfig schema for the prebake commands, read from
[tool.<cli>.prebake].Lets a project pin the target
__init__.pyonce for its build pipeline, instead of passing--moduleto everyclick-extra prebakecommand.
- class click_extra.config.builtin.ClickExtraConfig(test_suite=<factory>, prebake=<factory>)[source]
Bases:
objectSchema for the
[tool.click-extra]configuration section.Wired as the
config_schemaof the top-levelclick-extragroup, so every subcommand reads the same section and pulls its own sub-table throughget_tool_config().- test_suite: TestSuiteConfig
The
[tool.click-extra.test-suite]sub-table (file/cases/timeout).
- prebake: PrebakeConfig
The
[tool.click-extra.prebake]sub-table (target module).
classDiagram
Enum <|-- Sentinel
ExtraOption <|-- ConfigOption
ExtraOption <|-- ExportConfigOption
ExtraOption <|-- NoConfigOption
ExtraOption <|-- ValidateConfigOption
ParamStructure <|-- ConfigOption
Utilities to load parameters and options from a configuration file.
Hint
Why config?
That whole namespace is using the common config short-name to designate
configuration files.
Not conf, not cfg, not configuration, not settings. Just config.
A quick survey of existing practices, and poll to my friends informed me that
config is more explicit and less likely to be misunderstood.
After all, is there a chance for it to be misunderstood, in the context of a CLI, for something else? Confirm? Conference? Conflict Confuse?…
So yes, config is good enough.
Dotted keys in configuration files (like "subcommand.option": value) are
automatically expanded into nested dicts before merging, so users can freely mix
flat dot-notation and nested structures in any supported format.
- click_extra.config.option.get_app_dir(app_name, roaming=True, force_posix=False)
click.get_app_dir()’s Unix branch, taken on every platform.Returns an expanded path like the original, since a caller resolves it before Click Extra shrinks the home prefix back to
~for display.XDG_CONFIG_HOMEis deliberately ignored: honoring it would put the host back into the rendered output.
- click_extra.config.option.VCS_DIRS = ('.git', '.hg', '.svn', '.bzr', 'CVS', '.darcs')
VCS directory names used to identify version control system roots.
Includes: -
.git: Git -.hg: Mercurial -.svn: Subversion -.bzr: Bazaar -CVS: CVS (note: uppercase, no leading dot) -.darcs: Darcs
- click_extra.config.option.CONFIG_OPTION_NAME = 'config'
Hardcoded name of the configuration option.
This name is going to be shared by both the
--configand--no-configoptions below, so they can compete with each other to either set a path pattern or disable the use of any configuration file at all.
- click_extra.config.option.DEFAULT_EXCLUDED_PARAMS = ('config', 'export_config', 'params', 'validate_config', 'version')
Default parameter IDs to exclude from the configuration file.
Defaults to:
--configoption, which cannot be used to recursively load another configuration file.--export-configflag, which like--paramsintrospects the CLI and exits, so it has no place in the configuration it would export.--paramsflag, which is like--helpand stops the CLI execution.--validate-configoption, which belongs to the same self-referential config machinery as--configand--export-config.--version, which is not a configurable option per-se.
--helpis excluded too (it makes no sense to have a configuration file always force a CLI to show the help and exit), but is deliberately absent from this tuple: unlike the entries above, click-extra does not control that option’s internal name. It is resolved at runtime instead, inConfigOption.excluded_params, so a rename on Click’s own side does not silently stop excluding it.
- class click_extra.config.option.Sentinel(*values)[source]
Bases:
EnumEnum used to define sentinel values.
Note
This reuse the same pattern as
Click._utils.Sentinel.See also
- NO_CONFIG = <object object>
- VCS = <object object>
- click_extra.config.option.NO_CONFIG = Sentinel.NO_CONFIG
Sentinel used to indicate that no configuration file must be used at all.
- click_extra.config.option.VCS = Sentinel.VCS
Sentinel used to stop parent directory walking at the nearest VCS root.
- class click_extra.config.option.ConfigOption(param_decls=None, metavar='LOCATION', type=UNPROCESSED, help='Location of the configuration file. Supports local path with glob patterns or remote URL.', is_eager=True, expose_value=False, file_format_patterns=None, file_pattern_flags=4104, show_file_patterns=None, roaming=True, force_posix=False, search_pattern_flags=285504, search_parents=False, stop_at=Sentinel.VCS, cascade=False, excluded_params=None, included_params=None, strict=False, config_schema=None, schema_strict=False, fallback_sections=(), config_validators=(), **kwargs)[source]
Bases:
ExtraOption,ParamStructureA pre-configured option adding
--config LOCATION.Takes as input a path to a file or folder, a glob pattern, or an URL.
is_eageris active by default so thecallbackgets the opportunity to set thedefault_mapof the CLI before any other parameter is processed.defaultis set to the value returned byself.default_pattern(), which is a pattern combining the default configuration folder for the CLI (as returned byclick.get_app_dir()) and all supported file formats.Attention
Default search pattern must follow the syntax of wcmatch.glob.
excluded_paramsare parameters which, if present in the configuration file, will be ignored and not applied to the CLI. Items are expected to be the fully-qualified ID of the parameter, as produced in the output of--params. Will default to the value ofDEFAULT_EXCLUDED_PARAMS, plus the CLI’s--helpoption, resolved at runtime.included_paramsis the inverse ofexcluded_params: only the listed parameters will be loaded from the configuration file. Cannot be used together withexcluded_params.
- file_format_patterns: dict[ConfigFormat, tuple[str, ...]]
Mapping of
ConfigFormatto their associated file patterns.Can be a string or a sequence of strings. This defines which configuration file formats are supported, and which file patterns are used to search for them.
Note
All formats depending on third-party dependencies that are not installed will be ignored.
Attention
File patterns must follow the syntax of wcmatch.fnmatch.
- auto_file_formats
Whether the format set was inherited instead of chosen by the developer.
Truewhen nofile_format_patternswas provided, so the set is whatever the installed extra dependencies enable. It ranges from 3 patterns on a bare install to 14 with every extra, which is an artifact of the environment rather than a decision the CLI made.Only
collapse_default()reads it, and only whenshow_file_patternsis left atNone.
- file_pattern_flags
Flags provided to all calls of
wcmatch.fnmatch.Applies to the matching of file names against supported format patterns specified in
file_format_patterns.Important
The
SPLITflag is always forced, as our multi-pattern design relies on it.
- show_file_patterns
Whether the help screen prints the file patterns of the default.
Follows the tri-state convention of Click Extra’s other display settings:
Noneprints them when the developer chose the format set, and hides them when it was inherited from the install.Truealways prints them, which is how a CLI advertises the formats its own dependencies enable.Falsealways hides them.
See
collapse_default()for what each state renders.
- force_posix
Configuration for default folder search.
roamingandforce_posixare fed to click.get_app_dir() to determine the location of the default configuration folder.
- search_pattern_flags
Flags provided to all calls of
wcmatch.glob.Applies to both the default pattern and any user-provided pattern.
Important
The
BRACEflag is always forced, so that multi-format default patterns using{pat1,pat2,...}syntax expand correctly.The
NODIRflag is always forced, to optimize the search for files only.
- search_parents
Indicates whether to walk back the tree of parent folders when searching for configuration files.
- stop_at
Boundary for parent directory walking.
None: walk up to filesystem root.VCS: stop at the nearest VCS root, whichever system marks it (seeVCS_DIRS) (default).A
Pathorstr: stop at that directory.
- cascade
Merge every discovered configuration file instead of stopping at the first parseable one.
When
True, all files found by auto-discovery (the app-dir search, including the parent walk whensearch_parents=True, plus thepyproject.tomlCWD search when enabled) are loaded and layered into the context’sdefault_mapvia a~collections.ChainMap. The most local file wins on key lookup: apyproject.tomlfound near the CWD overrides the app-dir config, which overrides files found higher up the parent walk.An explicit
--configvalue never cascades: it pins a single source, whatever the pattern matches.Defaults to
False, which preserves the historical behavior of the first successfully parsed file winning.
- extra_excluded_params: frozenset[str]
Additional exclusions merged into the dynamic
excluded_paramsdefault.Populated by
Command’sexcluded_paramsforwarding, which is additive: the default blocklist (--config,--version,--help, …) is preserved and the forwarded IDs are unioned into it when the property resolves. Ignored when an explicitexcluded_paramswas frozen on the instance, as the property is then never consulted.
- included_params: frozenset[str] | None
Allowlist of parameter IDs, mutually exclusive with
excluded_params.Nonedisables the allowlist. It is resolved intoexcluded_paramsbybuild_param_trees(), once every parameter ID is known.
- strict
Defines the strictness of the configuration loading.
If
True, raise an error if the configuration file contain parameters not recognized by the CLI.If
False, silently ignore unrecognized parameters.
- config_schema
Optional schema for structured access to configuration values.
When set, the app’s configuration section is extracted from the parsed config file, normalized (hyphens replaced with underscores), flattened (nested dicts joined with
_), and passed to this callable to produce a typed configuration object.Supports:
Dataclass types: detected via
__dataclass_fields__. Keys are normalized, nested dicts are flattened, and the result is filtered to known fields before instantiation. This allows nested config sections (like[tool.myapp.sub-section]) to map directly to flat dataclass fields (likesub_section_key).Any callable
dict → T: called directly with the raw dict. Works with Pydantic’sModel.model_validate, attrs, or custom factory functions. The caller is responsible for key normalization and flattening.
The resulting object is stored in
ctx.meta[click_extra.context.TOOL_CONFIG]and can be retrieved viaget_tool_config.
- schema_strict
Strictness for schema validation (separate from
strict).If
True, raiseValueErrorwhen the config section contains keys that do not match any dataclass field (after normalization and flattening). Only applies whenconfig_schemais a dataclass.If
False, ignore unrecognized keys. When the section is schema-only (included_params=()), a warning still names them: seewarn_unknowninmake_schema_callable().
Note
This is distinct from
strict, which controls whethermerge_default_maprejects config keys not matching CLI parameters.schema_strictvalidates against dataclass fields instead.
- fallback_sections: Sequence[str]
Legacy section names to try when the app’s own section is empty.
Useful when a CLI tool has been renamed: old configuration files that still use
[tool.old-name](TOML),old-name:(YAML), or{"old-name": …}(JSON) are recognized with a deprecation warning. Works with all configuration formats.
- schema_warn_unknown: bool
Warn on config keys unknown to the schema, in lax mode.
Inferred, not user-supplied: an explicitly empty
included_paramsmeans no CLI parameter is merged from the app’s config section, so the section is schema-only and any key the schema does not know is a typo worth a warning. Forwarded tomake_schema_callable()and the validation pipeline aswarn_unknown.
- config_validators: tuple[ConfigValidator, ...]
Extension validators for sub-trees of the configuration file.
Each
ConfigValidatortargets a dottedextension_pathrelative to the app section. Validators run after click-extra’s built-in CLI-parameter strict check (during--validate-config) and after the schema callable produces the typed configuration object (during normal config loading).The list is seeded with click-extra’s built-in validators (currently the one for
[tool.<cli>.themes.<name>]tables, seeclick_extra.theme.validate_themes_config()); user-supplied validators are appended after them. App code that registers its own validator on the sameextension_pathsimply runs alongside the built-in: both validators are called, both sets of errors surface.
- property excluded_params: frozenset[str][source]
Generates the default list of fully-qualified IDs to exclude.
Danger
It is only called once to produce the default exclusion list if the user did not provided its own.
It was not implemented in the constructor but made as a property, to allow for a just-in-time call within the current context. Without this trick we could not have fetched the CLI name.
- property file_pattern: str[source]
Compile all file patterns from the supported formats.
Uses
,(comma) notation to combine multiple patterns, suitable forwcmatchbrace expansion ({pat1,pat2,...}).Returns a single pattern string.
- default_pattern()[source]
Returns the default pattern used to search for the configuration file.
Defaults to
<app_dir>/{*.toml,*.json,*.ini}. Where<app_dir>is produced by the click.get_app_dir() method. The result depends on OS and is influenced by theroamingandforce_posixproperties.Multiple file format patterns are wrapped with
{…}brace-expansion syntax so thatwcmatch.globcorrectly applies the directory prefix to every sub-pattern.Note
A CLI wanting another folder layout, like the one platformdirs computes, passes its own pattern to
defaultinstead. That keeps the layout a choice of the CLI rather than a dependency of this package: see the documentation.- Return type:
- get_help_extra(ctx)[source]
Replaces the default value of the configuration option.
Display a pretty path that is relative to the user’s home directory:
~/folder/my_cli/{*.toml,*.json,*.ini}Instead of the full absolute path:
/home/user/folder/my_cli/{*.toml,*.json,*.ini}- Return type:
OptionHelpExtra
Caution
This only applies when the
GLOBTILDEflag is set insearch_pattern_flags.An inherited format set is then reduced to the folder it searches, as described in
collapse_default().
- render_default(ctx)[source]
The default search pattern, as a portable home-relative path.
Keeps the whole pattern, file patterns included. The help screen collapses an inherited set on top of this with
collapse_default(), but a consumer with room for the files (theFILESsection of a man page) calls this method instead.- Return type:
- collapse_default(default)[source]
Reduce an inherited default pattern to the folder it searches.
A CLI installed with every extra searches 15 file patterns, so its default renders as a 136-character glob. The help screen has no space for it and no place to break it, so Click splits it mid-word:
[default: ~/.config/hello/{*. toml,*.yaml,*.yml,*.json,*.json5,*.jwcc,*.jsonc, *.hjson,*.ini,*.xml,*.plist,*.sqlite,*.sqlite3,* .conf,pyproject.toml}]Rendering the folder alone answers the question a reader opens
--helpfor, on one line, and keeps the answer the same on every install:[default: ~/.config/hello/]
A developer who passed
file_format_patternschose that set, so it is displayed in full: the pattern is short enough to read, and the help screen is where the choice shows up.show_file_patternsoverrides that reading in either direction, andTrueis what a CLI advertising its formats wants: the set is computed from the installed dependencies at each invocation, so the help screen reports what that install can really parse. The complete pattern of any CLI stays available in the output of--params.The trailing separator marks the value as a folder, since it is a search base and not a location the option accepts back.
- Return type:
- parent_patterns(pattern)[source]
Generate
(root_dir, file_pattern)pairs for searching.Each yielded pair can be passed directly to
glob.iglob(file_pattern, root_dir=root_dir)so that every sub-pattern (whether fromBRACEorSPLITexpansion) is correctly scoped to the same directory.root_dirisNonefor entirely magic patterns that will be evaluated relative to the current working directory.Stops when reaching the root folder, the
stop_atboundary, or an inaccessible directory.
- search_and_read_file(pattern)[source]
Search filesystem or URL for files matching the
pattern.If
patternis an URL, download its content. A pattern is considered an URL only if it validates as one and starts withhttp://orhttps://. All other patterns are considered glob patterns for local filesystem search.Returns an iterator of
(location, content, media_type)triples, for each one matching the pattern.locationis normalized andcontentraw.media_typeis the baretype/subtypethe server advertised in itsContent-Typeheader, and isNonefor a local file, whose format is derived from its name. Only files are returned, directories are silently skipped.This method returns the raw content of all matching patterns, without trying to parse them. If the content is empty, it is still returned as-is.
Also includes lookups into parents directories if
self.search_parentsisTrue.Raises
FileNotFoundErrorif no file was found after searching all locations.
- parse_conf(content, formats, location=None)[source]
Parse the
contentwith the givenformats.Tries to parse the given raw
contentstring with each of the givenformats, in order. Yields the resulting data structure for each successful parse.locationis the path thecontentwas read from. It is only needed by formats that cannot be parsed from a text payload, likeSQLITE, which is read straight from its file, and the binary variant ofPLIST, which only exists on disk. Such formats are skipped whenlocationis missing or is not a local file.Attention
Formats whose parsing raises an exception or does not return a
dictare considered a failure and are skipped.This follows the parse, don’t validate principle.
- read_and_parse_all_conf(pattern)[source]
Search for every parseable configuration file matching
pattern.Yields
(location, parsed_conf)pairs in discovery order, which is the most local first: the original search location, then each parent directory when parent search is enabled. Files already yielded (as matched by their resolved location) are skipped, as are files that parse to an empty configuration.Raises
FileNotFoundErrorif no file at all matched the pattern.
- read_and_parse_conf(pattern)[source]
Search for a parseable configuration file.
Returns the location and data structure of the first configuration matching the
pattern.Only return the first match that:
exists,
is a file,
is not empty,
match file format patterns,
can be parsed successfully, and
produce a non-empty data structure.
Raises
FileNotFoundErrorif no configuration file was found matching the criteria above.Returns
(None, None)if files were found but none could be parsed.
- load_ini_config(content)[source]
Utility method to parse INI configuration file.
Internal convention is to use a dot (
., as set byPARAM_PATH_SEP) in section IDs as a separator between levels. This is a workaround the limitation ofINIformat which doesn’t allow for sub-sections.Returns a ready-to-use data structure.
- load_argfile_config(content)[source]
Utility method to parse a plain-text argfile configuration file.
The file holds command-line tokens, one option per line, in the style of
mpv’s andyt-dlp’s configuration files:# Comments start with a hash sign. --option-name some value --flag
Tokens are split with
shlex.split(), so shell quoting rules apply and a#starts a comment. Each option is matched against the CLI’s root-level parameter declarations, and its value is converted to the parameter’s Python type, likeload_ini_config()does. A boolean flag needs no value: its primary declaration sets it toTrue, its secondary one (--no-*) toFalse. An option flaggedmultipleaccumulates one list item per occurrence. Unknown options are kept under a normalized key so the strict check can reject them like any other unrecognized configuration key, while positional tokens are skipped; subcommand options cannot be addressed from an argfile.Returns a ready-to-use data structure, wrapped in the app’s section name like the
[my-cli]section of the other formats.- Raises:
ValueError – the content cannot be tokenized, or an option is missing its value.
- Return type:
- load_sqlite_config(path)[source]
Utility method to parse a SQLite configuration database.
The database holds a single
SQLITE_CONFIG_TABLEtable ofkey/valuerows. Keys are parameter paths, with a dot (., as set byPARAM_PATH_SEP) separating each level, likemy-cli.default.int_param. Values are JSON-encoded, which carries every type the other formats do: booleans, numbers, strings, lists and nested objects alike.Returns a ready-to-use data structure.
Note
sqlite3is imported here and not at the top of the module, like the optional parsers ofparse_content(). A distribution can ship a Python without the SQLite bindings, and an unconditional import would then break every CLI at import time.SQLITE_SUPPORTreports whether they are there, and disables the format if they are not.
- load_plist_config(path)[source]
Utility method to parse a
plistconfiguration file.The file is read as raw bytes and handed to the standard library’s
plistlib, which transparently decodes both the XML and the binary variants of the format. The XML variant also parses from a text payload throughparse_content(), which is how aplistfetched overhttp://orhttps://is loaded.Returns a ready-to-use data structure.
- merge_default_map(ctx, user_conf)[source]
Save the user configuration into the context’s
default_map.Merge the user configuration into the pre-computed template structure, which filters out all unrecognized options not supported by the command, then hand the result to
_install_default_map().Opaque sub-trees declared by the schema or by registered
ConfigValidatorinstances are stripped from the conf before the CLI-parameter strict check, so user-controlled keys (like mappings whose keys are data, not flag names) don’t tripstrict=True.Note
This recomputes the filtered config that
run_config_validation()already produces asmerged_conf.load_conf()installs that result directly and skips this method; it stays as the standalone entry point for external callers.- Return type:
- load_conf(ctx, param, path_pattern)[source]
Fetch parameter values from a configuration file and set them as defaults.
User configuration is merged to the context’s default_map, like Click does.
By relying on Click’s
default_map, we make sure that precedence is respected. Direct CLI parameters, environment variables or interactive prompts take precedence over any values from the config file.Hint
Once loading is complete, the resolved file path and its full parsed content are stored in
ctx.meta[click_extra.context.CONF_SOURCE]andctx.meta[click_extra.context.CONF_FULL]respectively. This is the recommended way to identify which configuration file was loaded.We intentionally do not add a custom
ParameterSource.CONFIG_FILEenum member:ParameterSourceis a closed enum in Click, and monkeypatching it would be fragile. Besides, config values end up indefault_map, so Click already reports them asParameterSource.DEFAULT_MAP, which is accurate.- Return type:
- class click_extra.config.option.NoConfigOption(param_decls=None, help='Ignore all configuration files and only use command line parameters and environment variables.', is_flag=True, flag_value=Sentinel.NO_CONFIG, is_eager=True, expose_value=False, **kwargs)[source]
Bases:
ExtraOptionA pre-configured option adding
--no-config.This option is supposed to be used alongside the
--configoption (ConfigOption) to allow users to explicitly disable the use of any configuration file.This is especially useful to debug side-effects caused by autodetection of configuration files.
flag_value=NO_CONFIGis theSentinelenum member that signals “skip configuration loading” toConfigOption. Click8.4.0(PR pallets/click#3363) auto-detectstype=UNPROCESSEDfor non-basicflag_valuetypes, so the sentinel passes throughOptionunchanged without an explicittypeoverride.See also
An alternative implementation of this class would be to create a custom click.ParamType instead of a custom
Optionsubclass. Here is for example.
- class click_extra.config.option.ValidateConfigOption(param_decls=None, type=UNPROCESSED, metavar='LOCATION', is_eager=True, expose_value=False, help='Validate the configuration file and exit.', **kwargs)[source]
Bases:
ExtraOptionA pre-configured option adding
--validate-config LOCATION.Loads the config file at the given location, validates it against the CLI’s parameter structure in strict mode, reports results, and exits.
Note
The value is left
UNPROCESSEDso it accepts everythingConfigOptionaccepts: a file, a folder, a glob pattern, or anhttp://orhttps://URL. Both options hand their value to the sameConfigOption.read_and_parse_conf(), so a configuration a CLI can load is a configuration it can also validate.- validate_config(ctx, param, value)[source]
Load, parse, and validate the configuration file, then exit.
Validation runs three checks in order, every one of them under the same
ValidationErrorshape so the reported path is always rooted at the configuration file:CLI-parameter strict check on the non-opaque part of the document.
Schema processing, if a
config_schemais configured: catches type errors and unknown keys inside the dataclass-described section.Each registered
ConfigValidatorruns against its declared opaque sub-tree.
Every detected error is emitted before exiting, so a single
--validate-configrun surfaces the full list of fixes the user needs to apply.- Return type:
- click_extra.config.option.ensure_config_loaded(ctx)[source]
Run the sibling
ConfigOption’s resolution if it has not run yet.Click processes eager parameters given on the command line before eager parameters left at their defaults, so an explicitly-passed introspection flag (
--params,--export-config) fires before the--configoption had a chance to discover and load the configuration file. The views those flags render would then miss the configuration layer entirely, showing defaults where the user’s config applies.Idempotent: does nothing when the config option already resolved (its callback stamps
CONF_SOURCEon the context even when no file was found), when the command has no config option, or when the option carries no callback.- Return type:
- class click_extra.config.option.ExportConfigOption(param_decls=None, type=None, metavar='FORMAT', is_eager=True, expose_value=False, help='Export the configuration in the selected format to <stdout>, then exit.', **kwargs)[source]
Bases:
ExtraOptionA pre-configured option adding
--export-config FORMAT.Resolves the CLI’s current parameter values following Click’s precedence chain (command line, then environment variables, then configuration file, then defaults), renders them as a configuration file in the requested format on
<stdout>, and exits.Hint
Combine the flag with other options or environment variables to capture them in the generated configuration. For example,
mycli --verbosity DEBUG --export-config toml``emits a configuration whose``verbosityis already set toDEBUG.Like
ValidateConfigOption, it relies on a siblingConfigOptionto provide the parameter structure and theexcluded_params/included_paramsfilter, so the export contains exactly the parameters that can be loaded back from a configuration file.Note
The accepted formats are those
serialize_content()can write (SERIALIZABLE_FORMATS).INI,Argfileandpyproject.tomlhave no serializer and cannot be dumped.- build_config(ctx, config_option)[source]
Resolve every config-eligible parameter into a dumpable tree.
Walks the sibling
ConfigOption’s parameter structure, resolves each parameter’s effective value by replayingRAW_ARGS(falling back to defaults when the command did not capture them), drops theexcluded_params, and layers the coerced values into the{cli-name: {param: value, ...}}shape a configuration file uses. Parameter keys are rendered in their kebab-case spelling, the canonical presentation for configuration files; either spelling loads back to the same parameter.Parameters without a default are kept as
Noneleaves so the export names every key a configuration file can set: serializers render them asnull, except TOML which comments them out (see_serialize_toml_with_unset()). Loadingnullback is harmless:ConfigOption._install_default_map()cleans blank values out of the merged result.