click_extra.config package¶
Configuration file loading, format parsing, and schema validation.
This package gathers the three layers behind --config, --no-config, and
--validate-config:
formats: the supported file formats and their stateless content parsers.schema: the schema-building and validation engine.option: the option classes and click-extra’s own configuration schemas.
Every public symbol is re-exported here so consumers can keep importing from
click_extra.config.
- class click_extra.config.ClickExtraConfig(test_plan=<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_plan: TestPlanConfig¶
The
[tool.click-extra.test-plan]sub-table (file/inline/timeout).
- prebake: PrebakeConfig¶
The
[tool.click-extra.prebake]sub-table (target module).
- class click_extra.config.ConfigFormat(*values)[source]¶
Bases:
EnumAll configuration formats, associated to their support status.
The first element of the tuple is a sequence of file extensions associated to the format. Patterns are fed to
wcmatch.globfor matching, and are influenced by the flags set on theConfigOptioninstance.The second element indicates whether the format is supported or not, depending on the availability of the required third-party packages. This evaluation is performed at runtime when this module is imported.
Caution
The order is important for both format members and file patterns. It defines the priority order in which formats are tried when multiple candidate files are found.
- TOML = (('*.toml',), True, 'TOML')¶
- YAML = (('*.yaml', '*.yml'), True, 'YAML')¶
- JSON = (('*.json',), True, 'JSON')¶
- JSON5 = (('*.json5',), True, 'JSON5')¶
- JSONC = (('*.jsonc',), True, 'JSONC')¶
- HJSON = (('*.hjson',), True, 'Hjson')¶
- INI = (('*.ini',), True, 'INI')¶
- XML = (('*.xml',), True, 'XML')¶
- PYPROJECT_TOML = (('pyproject.toml',), True, 'pyproject.toml')¶
- class click_extra.config.ConfigOption(param_decls=None, metavar='CONFIG_PATH', 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, roaming=True, force_posix=False, search_pattern_flags=285504, search_parents=False, stop_at=Sentinel.VCS, 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 CONFIG_PATH.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--show-params. Will default to the value ofDEFAULT_EXCLUDED_PARAMS.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.
- 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.
- 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 (.gitor.hg) (default).A
Pathorstr: stop at that directory.
- 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 via get_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, silently ignore unrecognized keys.
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.
- 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.Todo
Use platformdirs for more advanced configuration folder detection?
- 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}Caution
This only applies when the
GLOBTILDEflag is set insearch_pattern_flags.- Return type:
OptionHelpExtra
- 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 the normalized location and its raw content, for each one matching the pattern. 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)[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.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_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.
- 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.ConfigValidator(extension_path, validator, description='')[source]¶
Bases:
objectRegister an app-defined extension validator for one sub-tree of the configuration file.
Apps register validators via the
config_validators=kwarg onConfigOption(or the matching decorator) to extend click-extra’s built-in CLI-parameter strict check with custom validation logic. Each validator targets a single dottedextension_pathrelative to the app’s configuration section. Click-extra passes the matching sub-tree straight through to the registered validator: the strict check skips it, the schema machinery treats it as opaque, and the user’s logic owns the result. The validator runs both during--validate-configand during normal config loading.- Parameters:
extension_path (
str) – Dotted path of the sub-tree the validator owns, relative to the app’s section in the configuration file. For example, an app namedmy-cliwithextension_path="managers"receives the contents of the[my-cli.managers]table.validator (
Callable[[dict[str,Any]],None]) – Callable taking the sub-tree dict and raisingValidationErroron failure. Must be a pure function: no side effects on the click context, no print statements. The caller decides how to surface the error.description (
str) – Optional human-readable summary of what the validator checks. Surfaces in documentation generators that introspect the decorator (like autodoc), and may be reused in--helptext in a future release.
- class click_extra.config.NoConfigOption(param_decls=None, type=UNPROCESSED, 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, but click-extra still supports Click8.3.xwhere that auto-detection is absent, so thetype=UNPROCESSEDoverride is kept explicit to let the sentinel pass throughOptionunchanged on every supported Click.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.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.TestPlanConfig(file='./tests/cli-test-plan.yaml', inline=None, timeout=None)[source]¶
Bases:
objectConfig schema for a project’s test plan, read from
[tool.<cli>.test-plan].The
test-planCLI command resolves its cases from this config when no plan is given on the command line. Map it onto an app’s config section with a field carryingmetadata={"click_extra.config_path": "test-plan"}.
- class click_extra.config.ValidateConfigOption(param_decls=None, type=<click.types.Path object>, is_eager=True, expose_value=False, help='Validate the configuration file and exit.', **kwargs)[source]¶
Bases:
ExtraOptionA pre-configured option adding
--validate-config CONFIG_PATH.Loads the config file at the given path, validates it against the CLI’s parameter structure in strict mode, reports results, and exits.
- 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:
- exception click_extra.config.ValidationError(path, message, code=None)[source]¶
Bases:
ExceptionRaised when a configuration file fails validation.
A single, structured exception type that uniformly carries the dotted
pathof the offending key, a human-readablemessage, and an optionalcodefor programmatic handling. Used by click-extra’s built-in strict-mode check and by every user-registeredConfigValidator, so downstream apps and--validate-configsee the same error shape regardless of who detected the problem.- Parameters:
path (
str) – Dotted path to the offending key, relative to the configuration file root (like"my-cli.managers.winget.cli_searchpath"). An empty string means the error applies to the document as a whole.message (
str) – Human-readable description of the failure. Should be a single sentence, no trailing punctuation, no path repeated.code (
str|None) – Optional machine-readable error code (like"unknown_field") for callers that want to dispatch on error type without parsing the message string.
- class click_extra.config.ValidationReport(schema_instance, opaque_subtrees, errors, merged_conf=None)[source]¶
Bases:
objectOutcome of one pass through
run_config_validation().Bundles everything a caller needs after validating a parsed configuration document: the typed schema instance, the extracted opaque sub-trees, the template-filtered config ready for
default_map, and every error detected across all validation stages.Note
The report holds references to the parsed sub-trees, not copies, so building it is cheap regardless of document size.
- schema_instance: Any | None¶
Typed object produced by the configured schema callable.
Nonewhen no schema is configured, or when the schema stage raised (in which case the failure is recorded inerrors).
- opaque_subtrees: dict[str, dict[str, Any]]¶
Extracted extension sub-trees, keyed by dotted path relative to the app section. Only paths actually present in the document appear here, so callers can re-route them to per-path validators or stash them on
ctx.meta.
- errors: tuple[ValidationError, ...]¶
Every
ValidationErrordetected, in stage order (unknown CLI-flag keys first, then schema errors, then validator failures). Empty on success.With
collect_all=Falsethis holds at most one error: the first failure short-circuits the remaining stages.
- merged_conf: dict[str, Any] | None = None¶
The CLI-flag-bound configuration merged onto
params_template: the payload_install_default_map()layers into the context’sdefault_map.Nonewhenparams_templatewasNone(no strict check) or the strict check raised. Read it only on a successful report: it is the same valuemerge_default_map()would recompute, so reusing it avoids a second normalize/strip/merge pass.
- click_extra.config.flatten_config_keys(conf, sep='_', opaque_keys=frozenset({}), _prefix='')[source]¶
Flatten nested dicts into a single level by joining keys with a separator.
Useful for mapping nested configuration structures (like TOML sub-tables) to flat Python dataclass fields. After normalization with normalize_config_keys, the flattened keys match dataclass field names directly:
>>> from click_extra.config import ( ... flatten_config_keys, ... normalize_config_keys, ... ) >>> raw = {"dependency-graph": {"all-groups": True, "output": "deps.mmd"}} >>> flatten_config_keys(normalize_config_keys(raw)) {'dependency_graph_all_groups': True, 'dependency_graph_output': 'deps.mmd'}
- Parameters:
sep (
str) – Separator used to join parent and child keys. Defaults to"_"which produces valid Python identifiers when combined with normalize_config_keys.opaque_keys (
frozenset[str]) – Fully-qualified key names where flattening stops. When the accumulated key matches an entry in this set, the dict value is kept as-is instead of being recursively flattened. This is useful for fields typed asdict[str, X]where the dict keys are data (like GitHub Actions matrix axis names), not config structure._prefix (
str) – Internal parameter for tracking the accumulated key path during recursion. Callers should not set this.
- Return type:
- click_extra.config.get_tool_config(ctx=None)[source]¶
Retrieve the typed tool configuration from the context.
Returns the object stored under
click_extra.context.TOOL_CONFIGbyConfigOptionwhen aconfig_schemais set, orNoneif no schema was configured or no configuration was loaded.
- click_extra.config.make_schema_callable(schema, *, strict=False, normalize=True)[source]¶
Wrap a schema type into a callable that accepts a raw config dict.
Dataclass types (detected via
dataclasses.is_dataclass) are auto-wrapped: keys are normalized (hyphens to underscores), nested dicts are flattened, and the result is filtered to known fields before instantiation. Three schema-aware features refine this process:Type-aware flattening. Fields typed as
dict[str, X]are treated as opaque:flatten_config_keysstops at their boundary so the dict value is kept intact.Field metadata. Dataclass fields may carry
click_extra.config_path(a dotted TOML path like"test-matrix.replace") andclick_extra.normalize_keys(Falseto skip key normalization on the extracted value). Fields with an explicit path are extracted from the raw config before normalization and flattening.Nested dataclass support. Fields whose resolved type is itself a dataclass are recursively processed with the same logic.
Any other callable is returned as-is. The caller is responsible for key normalization if needed.
NonereturnsNone.
- Parameters:
strict (
bool) – IfTrue, raiseValueErrorwhen the config contains keys that do not match any dataclass field (after normalization and flattening).normalize (
bool) – IfFalse, skipnormalize_config_keyson the remaining config dict. Used internally when recursing into nested dataclasses whose parent opted out of normalization viaclick_extra.normalize_keys = False.
- Return type:
- click_extra.config.normalize_config_keys(conf, opaque_keys=frozenset({}), _prefix='')[source]¶
Normalize configuration keys to valid Python identifiers.
Recursively replaces hyphens with underscores in all dict keys, using the same
str.replace("-", "_")transform that Click applies internally when deriving parameter names from option declarations (--foo-barbecomesfoo_bar). Click does not expose this as a public function, so we replicate the one-liner here.Handles the convention mismatch between configuration formats (TOML, YAML, JSON all commonly use kebab-case) and Python identifiers. Works with all configuration formats supported by
ConfigOption.- Parameters:
opaque_keys (
frozenset[str]) – Fully-qualified key names (using"_"as separator) where recursion stops. The key itself is still normalized, but its dict value is kept as-is. Used in tandem withflatten_config_keys’sopaque_keysto protect data dicts (like GitHub Actions matrix axes) from normalization._prefix (
str) – Internal parameter for tracking the accumulated key path during recursion. Callers should not set this.
Todo
Propose upstream to Click to extract the inline
name.replace("-", "_")into a private_normalize_param_namehelper, so downstream projects like Click Extra can reuse it instead of duplicating the transform.
- click_extra.config.run_config_validation(user_conf, *, app_name, params_template, config_schema=None, config_validators=(), fallback_sections=(), schema_strict=False, strict=False, collect_all=True)[source]¶
Validate a parsed configuration document in one schema-driven pass.
This is the module-level entry point that unifies click-extra’s three historical validation paths (CLI-parameter strict check, dataclass schema, and app-registered
ConfigValidatorhooks) behind a single function yielding a single error type. It is deliberately not namedvalidate_config: that name belongs tovalidate_config(), the callback powering the--validate-configflag.Stages, in order:
Normalize. Strip reserved keys and expand dotted keys.
Partition. Split opaque sub-trees (schema extension fields plus every registered validator’s
extension_path) from the CLI-flag-bound content. Extracted sub-trees land inValidationReport.opaque_subtrees.Strict-check the CLI-flag-bound part against
params_template, keeping the merged result asValidationReport.merged_conf(skipped whenparams_templateisNone).Schema-build the app section through the configured callable, producing
ValidationReport.schema_instance.Validate every opaque sub-tree through its registered validator.
- Parameters:
user_conf (
dict[str,Any]) – The full parsed configuration document.app_name (
str) – Name of the app’s section (used to resolve the section and to root opaque paths and error paths at the document level).params_template (
dict[str,Any] |None) – The CLI-parameter template the strict check runs against. PassNoneto skip the strict check entirely (for example, for a schema-only validation).config_schema (
type|Callable[[dict[str,Any]],Any] |None) – Dataclass type or callable describing the typed configuration, orNone.config_validators (
Sequence[ConfigValidator]) – Extension validators to run against opaque sub-trees.fallback_sections (
Sequence[str]) – Legacy section names to try whenapp_nameis absent or empty.schema_strict (
bool) – Reject keys the dataclass schema does not recognize.strict (
bool) – Reject keys the CLI-parameter template does not recognize.collect_all (
bool) – WhenTrue(default), run every stage and collect all errors. WhenFalse, the first error short-circuits the rest.
- Return type:
- Returns:
A
ValidationReport.ValidationErroris the single error type recorded by every stage;ValueError/TypeErrorraised by the strict check or schema callable are wrapped into it.
Submodules¶
click_extra.config.formats module¶
Configuration file formats and their stateless content parsers.
Holds the ConfigFormat enum, the optional third-party parser probes
that decide which formats are enabled, and parse_content(), the stateless
dispatch used by ConfigOption for every format that
does not need the CLI parameter structure.
- click_extra.config.formats.PARSER_SUPPORT: dict[str, bool] = {'hjson': True, 'json5': True, 'jsonc': True, 'xml': True, 'yaml': True}¶
Availability of each optional parser, keyed by
click-extra[extra]name.Populated once at import time by probing each module in
_OPTIONAL_PARSERSwithimportlib.util.find_spec(). Read byConfigFormatto mark the matching format as enabled or disabled. The probe does not import the module, so the actual parser is loaded lazily byparse_content()only when used.
- class click_extra.config.formats.ConfigFormat(*values)[source]¶
Bases:
EnumAll configuration formats, associated to their support status.
The first element of the tuple is a sequence of file extensions associated to the format. Patterns are fed to
wcmatch.globfor matching, and are influenced by the flags set on theConfigOptioninstance.The second element indicates whether the format is supported or not, depending on the availability of the required third-party packages. This evaluation is performed at runtime when this module is imported.
Caution
The order is important for both format members and file patterns. It defines the priority order in which formats are tried when multiple candidate files are found.
- TOML = (('*.toml',), True, 'TOML')¶
- YAML = (('*.yaml', '*.yml'), True, 'YAML')¶
- JSON = (('*.json',), True, 'JSON')¶
- JSON5 = (('*.json5',), True, 'JSON5')¶
- JSONC = (('*.jsonc',), True, 'JSONC')¶
- HJSON = (('*.hjson',), True, 'Hjson')¶
- INI = (('*.ini',), True, 'INI')¶
- XML = (('*.xml',), True, 'XML')¶
- PYPROJECT_TOML = (('pyproject.toml',), True, 'pyproject.toml')¶
- click_extra.config.formats.parse_content(fmt, content)[source]¶
Parse content with a single stateless format.
INI is excluded: it needs the CLI parameter structure for type coercion and is handled by ConfigOption.load_ini_config.
Note
Optional third-party parsers are imported lazily, at the point of use, rather than at module load. Only enabled formats reach this function (disabled ones are filtered out of
ConfigOption.file_format_patterns), so the import always resolves for the formats actually parsed here.- Return type:
click_extra.config.option module¶
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.
Todo
Add a --dump-config or --export-config option to write down the current
configuration (or a template) into a file or <stdout>.
Help message would be: you can use this option with other options or environment variables to have them set in the generated configuration.
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.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', 'help', 'show_params', 'version')¶
Default parameter IDs to exclude from the configuration file.
Defaults to:
--configoption, which cannot be used to recursively load another configuration file.--help, as it makes no sense to have the configurable file always forces a CLI to show the help and exit.--show-paramsflag, which is like--helpand stops the CLI execution.--version, which is not a configurable option per-se.
- 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='CONFIG_PATH', 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, roaming=True, force_posix=False, search_pattern_flags=285504, search_parents=False, stop_at=Sentinel.VCS, 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 CONFIG_PATH.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--show-params. Will default to the value ofDEFAULT_EXCLUDED_PARAMS.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.
- 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.
- 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 (.gitor.hg) (default).A
Pathorstr: stop at that directory.
- 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 via get_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, silently ignore unrecognized keys.
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.
- 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.Todo
Use platformdirs for more advanced configuration folder detection?
- 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}Caution
This only applies when the
GLOBTILDEflag is set insearch_pattern_flags.- Return type:
OptionHelpExtra
- 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 the normalized location and its raw content, for each one matching the pattern. 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)[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.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_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.
- 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, type=UNPROCESSED, 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, but click-extra still supports Click8.3.xwhere that auto-detection is absent, so thetype=UNPROCESSEDoverride is kept explicit to let the sentinel pass throughOptionunchanged on every supported Click.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=<click.types.Path object>, is_eager=True, expose_value=False, help='Validate the configuration file and exit.', **kwargs)[source]¶
Bases:
ExtraOptionA pre-configured option adding
--validate-config CONFIG_PATH.Loads the config file at the given path, validates it against the CLI’s parameter structure in strict mode, reports results, and exits.
- 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:
- class click_extra.config.option.TestPlanConfig(file='./tests/cli-test-plan.yaml', inline=None, timeout=None)[source]¶
Bases:
objectConfig schema for a project’s test plan, read from
[tool.<cli>.test-plan].The
test-planCLI command resolves its cases from this config when no plan is given on the command line. Map it onto an app’s config section with a field carryingmetadata={"click_extra.config_path": "test-plan"}.
- class click_extra.config.option.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.option.ClickExtraConfig(test_plan=<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_plan: TestPlanConfig¶
The
[tool.click-extra.test-plan]sub-table (file/inline/timeout).
- prebake: PrebakeConfig¶
The
[tool.click-extra.prebake]sub-table (target module).
click_extra.config.schema module¶
Schema-building and validation engine behind config_option and –validate-config.
- click_extra.config.schema.DEFAULT_SUBCOMMANDS_KEY = '_default_subcommands'¶
Reserved configuration key for specifying default subcommands.
When a group is invoked without explicit subcommands on the CLI, the subcommands listed under this key execute automatically in order. CLI always wins: if the user names subcommands explicitly, the config is ignored.
Example TOML configuration:
[my-cli] _default_subcommands = ["backup", "sync"] [my-cli.backup] path = "/home"
- click_extra.config.schema.PREPEND_SUBCOMMANDS_KEY = '_prepend_subcommands'¶
Reserved configuration key for prepending subcommands to every invocation.
Unlike
_default_subcommandswhich only fires when no subcommands are given on the CLI,_prepend_subcommandsalways prepends the listed subcommands. This is useful for always injecting adebugsubcommand on a dev machine, for example.Only works with
chain=Truegroups (non-chained groups resolve exactly one subcommand, so prepending would break the user’s intended command).Example TOML configuration:
[my-cli] _prepend_subcommands = ["debug"]
- click_extra.config.schema.EXTENSION_METADATA_KEY = 'click_extra.extension'¶
Dataclass field metadata flag marking a field as an extension point.
Schema authors set
metadata={EXTENSION_METADATA_KEY: True}on a field when its sub-tree should pass through click-extra’s CLI-parameter strict check and be validated by app-specific logic instead. Equivalent to typing the field asdict[str, X]: both forms are recognized by_collect_opaque_paths_from_schema(the internal pipeline still calls these paths “opaque” since they’re skipped by the normalize/flatten/strict machinery). The metadata form is useful when the underlying Python type is something other than adict(for example, a nested dataclass that nonetheless represents user-extensible content).
- click_extra.config.schema.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().
- exception click_extra.config.schema.ValidationError(path, message, code=None)[source]¶
Bases:
ExceptionRaised when a configuration file fails validation.
A single, structured exception type that uniformly carries the dotted
pathof the offending key, a human-readablemessage, and an optionalcodefor programmatic handling. Used by click-extra’s built-in strict-mode check and by every user-registeredConfigValidator, so downstream apps and--validate-configsee the same error shape regardless of who detected the problem.- Parameters:
path (
str) – Dotted path to the offending key, relative to the configuration file root (like"my-cli.managers.winget.cli_searchpath"). An empty string means the error applies to the document as a whole.message (
str) – Human-readable description of the failure. Should be a single sentence, no trailing punctuation, no path repeated.code (
str|None) – Optional machine-readable error code (like"unknown_field") for callers that want to dispatch on error type without parsing the message string.
- class click_extra.config.schema.ConfigValidator(extension_path, validator, description='')[source]¶
Bases:
objectRegister an app-defined extension validator for one sub-tree of the configuration file.
Apps register validators via the
config_validators=kwarg onConfigOption(or the matching decorator) to extend click-extra’s built-in CLI-parameter strict check with custom validation logic. Each validator targets a single dottedextension_pathrelative to the app’s configuration section. Click-extra passes the matching sub-tree straight through to the registered validator: the strict check skips it, the schema machinery treats it as opaque, and the user’s logic owns the result. The validator runs both during--validate-configand during normal config loading.- Parameters:
extension_path (
str) – Dotted path of the sub-tree the validator owns, relative to the app’s section in the configuration file. For example, an app namedmy-cliwithextension_path="managers"receives the contents of the[my-cli.managers]table.validator (
Callable[[dict[str,Any]],None]) – Callable taking the sub-tree dict and raisingValidationErroron failure. Must be a pure function: no side effects on the click context, no print statements. The caller decides how to surface the error.description (
str) – Optional human-readable summary of what the validator checks. Surfaces in documentation generators that introspect the decorator (like autodoc), and may be reused in--helptext in a future release.
- click_extra.config.schema.normalize_config_keys(conf, opaque_keys=frozenset({}), _prefix='')[source]¶
Normalize configuration keys to valid Python identifiers.
Recursively replaces hyphens with underscores in all dict keys, using the same
str.replace("-", "_")transform that Click applies internally when deriving parameter names from option declarations (--foo-barbecomesfoo_bar). Click does not expose this as a public function, so we replicate the one-liner here.Handles the convention mismatch between configuration formats (TOML, YAML, JSON all commonly use kebab-case) and Python identifiers. Works with all configuration formats supported by
ConfigOption.- Parameters:
opaque_keys (
frozenset[str]) – Fully-qualified key names (using"_"as separator) where recursion stops. The key itself is still normalized, but its dict value is kept as-is. Used in tandem withflatten_config_keys’sopaque_keysto protect data dicts (like GitHub Actions matrix axes) from normalization._prefix (
str) – Internal parameter for tracking the accumulated key path during recursion. Callers should not set this.
Todo
Propose upstream to Click to extract the inline
name.replace("-", "_")into a private_normalize_param_namehelper, so downstream projects like Click Extra can reuse it instead of duplicating the transform.
- click_extra.config.schema.flatten_config_keys(conf, sep='_', opaque_keys=frozenset({}), _prefix='')[source]¶
Flatten nested dicts into a single level by joining keys with a separator.
Useful for mapping nested configuration structures (like TOML sub-tables) to flat Python dataclass fields. After normalization with normalize_config_keys, the flattened keys match dataclass field names directly:
>>> from click_extra.config import ( ... flatten_config_keys, ... normalize_config_keys, ... ) >>> raw = {"dependency-graph": {"all-groups": True, "output": "deps.mmd"}} >>> flatten_config_keys(normalize_config_keys(raw)) {'dependency_graph_all_groups': True, 'dependency_graph_output': 'deps.mmd'}
- Parameters:
sep (
str) – Separator used to join parent and child keys. Defaults to"_"which produces valid Python identifiers when combined with normalize_config_keys.opaque_keys (
frozenset[str]) – Fully-qualified key names where flattening stops. When the accumulated key matches an entry in this set, the dict value is kept as-is instead of being recursively flattened. This is useful for fields typed asdict[str, X]where the dict keys are data (like GitHub Actions matrix axis names), not config structure._prefix (
str) – Internal parameter for tracking the accumulated key path during recursion. Callers should not set this.
- Return type:
- click_extra.config.schema.get_tool_config(ctx=None)[source]¶
Retrieve the typed tool configuration from the context.
Returns the object stored under
click_extra.context.TOOL_CONFIGbyConfigOptionwhen aconfig_schemais set, orNoneif no schema was configured or no configuration was loaded.
- click_extra.config.schema.make_schema_callable(schema, *, strict=False, normalize=True)[source]¶
Wrap a schema type into a callable that accepts a raw config dict.
Dataclass types (detected via
dataclasses.is_dataclass) are auto-wrapped: keys are normalized (hyphens to underscores), nested dicts are flattened, and the result is filtered to known fields before instantiation. Three schema-aware features refine this process:Type-aware flattening. Fields typed as
dict[str, X]are treated as opaque:flatten_config_keysstops at their boundary so the dict value is kept intact.Field metadata. Dataclass fields may carry
click_extra.config_path(a dotted TOML path like"test-matrix.replace") andclick_extra.normalize_keys(Falseto skip key normalization on the extracted value). Fields with an explicit path are extracted from the raw config before normalization and flattening.Nested dataclass support. Fields whose resolved type is itself a dataclass are recursively processed with the same logic.
Any other callable is returned as-is. The caller is responsible for key normalization if needed.
NonereturnsNone.
- Parameters:
strict (
bool) – IfTrue, raiseValueErrorwhen the config contains keys that do not match any dataclass field (after normalization and flattening).normalize (
bool) – IfFalse, skipnormalize_config_keyson the remaining config dict. Used internally when recursing into nested dataclasses whose parent opted out of normalization viaclick_extra.normalize_keys = False.
- Return type:
- class click_extra.config.schema.ValidationReport(schema_instance, opaque_subtrees, errors, merged_conf=None)[source]¶
Bases:
objectOutcome of one pass through
run_config_validation().Bundles everything a caller needs after validating a parsed configuration document: the typed schema instance, the extracted opaque sub-trees, the template-filtered config ready for
default_map, and every error detected across all validation stages.Note
The report holds references to the parsed sub-trees, not copies, so building it is cheap regardless of document size.
- schema_instance: Any | None¶
Typed object produced by the configured schema callable.
Nonewhen no schema is configured, or when the schema stage raised (in which case the failure is recorded inerrors).
- opaque_subtrees: dict[str, dict[str, Any]]¶
Extracted extension sub-trees, keyed by dotted path relative to the app section. Only paths actually present in the document appear here, so callers can re-route them to per-path validators or stash them on
ctx.meta.
- errors: tuple[ValidationError, ...]¶
Every
ValidationErrordetected, in stage order (unknown CLI-flag keys first, then schema errors, then validator failures). Empty on success.With
collect_all=Falsethis holds at most one error: the first failure short-circuits the remaining stages.
- merged_conf: dict[str, Any] | None = None¶
The CLI-flag-bound configuration merged onto
params_template: the payload_install_default_map()layers into the context’sdefault_map.Nonewhenparams_templatewasNone(no strict check) or the strict check raised. Read it only on a successful report: it is the same valuemerge_default_map()would recompute, so reusing it avoids a second normalize/strip/merge pass.
- click_extra.config.schema.run_config_validation(user_conf, *, app_name, params_template, config_schema=None, config_validators=(), fallback_sections=(), schema_strict=False, strict=False, collect_all=True)[source]¶
Validate a parsed configuration document in one schema-driven pass.
This is the module-level entry point that unifies click-extra’s three historical validation paths (CLI-parameter strict check, dataclass schema, and app-registered
ConfigValidatorhooks) behind a single function yielding a single error type. It is deliberately not namedvalidate_config: that name belongs tovalidate_config(), the callback powering the--validate-configflag.Stages, in order:
Normalize. Strip reserved keys and expand dotted keys.
Partition. Split opaque sub-trees (schema extension fields plus every registered validator’s
extension_path) from the CLI-flag-bound content. Extracted sub-trees land inValidationReport.opaque_subtrees.Strict-check the CLI-flag-bound part against
params_template, keeping the merged result asValidationReport.merged_conf(skipped whenparams_templateisNone).Schema-build the app section through the configured callable, producing
ValidationReport.schema_instance.Validate every opaque sub-tree through its registered validator.
- Parameters:
user_conf (
dict[str,Any]) – The full parsed configuration document.app_name (
str) – Name of the app’s section (used to resolve the section and to root opaque paths and error paths at the document level).params_template (
dict[str,Any] |None) – The CLI-parameter template the strict check runs against. PassNoneto skip the strict check entirely (for example, for a schema-only validation).config_schema (
type|Callable[[dict[str,Any]],Any] |None) – Dataclass type or callable describing the typed configuration, orNone.config_validators (
Sequence[ConfigValidator]) – Extension validators to run against opaque sub-trees.fallback_sections (
Sequence[str]) – Legacy section names to try whenapp_nameis absent or empty.schema_strict (
bool) – Reject keys the dataclass schema does not recognize.strict (
bool) – Reject keys the CLI-parameter template does not recognize.collect_all (
bool) – WhenTrue(default), run every stage and collect all errors. WhenFalse, the first error short-circuits the rest.
- Return type:
- Returns:
A
ValidationReport.ValidationErroris the single error type recorded by every stage;ValueError/TypeErrorraised by the strict check or schema callable are wrapped into it.