meta_package_manager.config module¶

Configuration utilities for mpm.

Hosts the schema of the [mpm] configuration section consumed by click_extra and the runtime policy around the [mpm.managers.<id>] sections of the same configuration file: applying attribute overrides to shipped managers, gating manager definitions on the trust of their source, and registering them into the pool.

The concerns stay separate across three modules: meta_package_manager.pool.ManagerPool owns the live manager instances and the per-manager overridden_fields tracking dict; meta_package_manager.definitions owns the declarative schema (which fields a section may set, how to coerce values) and the class factory; this module owns the loading policy and mutates the pool through the apply_manager_overrides() and register_config_managers() helpers.

class meta_package_manager.config.MpmConfig(all_managers=False, ignore_auto_updates=True, stop_on_error=False, dry_run=False, plan=False, sudo=None, timeout=None, jobs='auto', cooldown=<factory>, description=False, sort_by=<factory>, summary=True, network=False, suggest_contribs=True, managers=<factory>)[source]¶

Bases: object

Schema for mpm configuration files.

Defines the recognized options for the [mpm] (or [tool.mpm]) configuration section. Each field corresponds to a CLI option on the root mpm group.

Note

Dynamic manager selectors (brew = true, pip = false, etc.), click-extra built-in options (verbosity, table_format) and one-shot utility flags (--bar-plugin-path, --xkcd) are handled by the default_map pipeline and do not appear here.

Note

Multi-word fields pin their config path through CONFIG_PATH_METADATA_KEY: mpm’s configuration convention is underscored keys (matching Click parameter names, the --validate-config checks and every documented example), while click-extra would otherwise kebab-case field names in the rendered click:config reference.

all_managers: bool = False¶

Force evaluation of all managers, including unsupported and unmaintained.

ignore_auto_updates: bool = True¶

Exclude auto-updating packages from outdated/upgrade results.

stop_on_error: bool = False¶

Stop on first manager CLI error instead of continuing.

dry_run: bool = False¶

Simulate CLI calls without performing any action.

plan: bool = False¶

Capture the state-changing CLI calls for inspection instead of running them.

sudo: bool | None = None¶

Force privileged manager operations with (True) or without (False) sudo. Unset by default: system managers escalate, user-level managers do not. Overridden per manager by a sudo entry in [mpm.managers.<id>].

timeout: int | None = None¶

Maximum duration in seconds for each manager CLI call. When unset, a per-operation default applies: 120 for read-only queries (installed, outdated, search) and 500 for state-changing operations. A set value overrides every operation.

jobs: int | str = 'auto'¶

Maximum number of managers to run concurrently. Accepts an integer, or the keywords auto (one fewer than the logical CPU count, the default) and max (every logical CPU); set 1 to run sequentially.

cooldown: dict[str, Any]¶

Release-age cooldown gate: period is the minimum age a package version must reach before it can be installed or upgraded, policy the posture for managers that cannot enforce it (enforce skips them, best-effort runs them without the safeguard).

Typed as dict[str, Any] so click-extra treats the [mpm.cooldown] sub-tree as opaque: it carries no CLI flag of its own (the --cooldown option merges over it axis by axis at runtime instead) and its keys are validated by validate_cooldown_section(), registered as a click_extra.ConfigValidator. The deprecated [mpm] cooldown = “<duration>” string spelling stays accepted as the period.

description: bool = False¶

Show package description in results.

sort_by: list[str]¶

Default fields to sort results by, in priority order.

summary: bool = True¶

Print an end-of-run summary on stderr: a count line of per-manager totals plus any subcommand-specific follow-up notes.

network: bool = False¶

Opt into network calls during the run. Today this only affects mpm sbom, which queries OSV.dev for vulnerability data.

suggest_contribs: bool = True¶

Print a contribution invitation when a user override targets a field that likely indicates an upstream detection bug.

managers: dict[str, dict]¶

Per-manager attribute overrides keyed by manager ID.

Typed as dict[str, dict] so click-extra treats the sub-tree as opaque: its keys are manager IDs (data, not flag names) and its leaf entries are validated by validate_manager_overrides_section() registered as a click_extra.ConfigValidator. The field carries no CLI flag — it only exists in the schema to declare opacity and to enable --validate-config coverage of the override block.

meta_package_manager.config.INVALIDATED_CACHED_PROPS: Final[tuple[str, ...]] = ('available', 'cli_path', 'executable', 'fresh', 'supported', 'version')¶

Cached properties on meta_package_manager.manager.PackageManager that may have been computed from attributes covered by OVERRIDABLE_FIELDS.

Any pre-computed values are popped from the manager instance’s __dict__ after an override is applied so the next access recomputes them against the new attribute values. Safe to pop even if nothing was cached.

meta_package_manager.config.CONTRIBUTION_HINT_FIELDS: Final[frozenset[str]] = frozenset({'cli_names', 'cli_search_path', 'requirement', 'version_cli_options', 'version_regexes'})¶

Subset of OVERRIDABLE_FIELDS whose override probably reflects a real upstream detection bug rather than a personal preference.

When the user overrides one of these, mpm did not find the binary, used the wrong binary name, rejected a valid version, or failed to parse one. The other overridable fields (timeout, ignore_auto_updates, pre_args, etc.) are user preferences and do not warrant a contribution invitation.

meta_package_manager.config.ISSUE_TRACKER_NEW_URL: Final[str] = 'https://github.com/kdeldycke/meta-package-manager/issues/new'¶

Base URL of the upstream GitHub issue tracker’s new-issue endpoint.

meta_package_manager.config.MAX_ISSUE_URL_LENGTH: Final[int] = 8192¶

Practical upper bound on the length of a pre-filled GitHub new-issue URL.

GitHub silently truncates very long URLs, which yields a broken issue form when the user clicks the invitation. Anything past 8 KiB is treated as a bug in the URL builder rather than a configuration we should tolerate.

class meta_package_manager.config.ContributionHint(manager_id, field, user_value, detected_cli_path)[source]¶

Bases: object

A user override of a detection-related field, candidate for upstream contribution.

Captured at override time by apply_manager_overrides() so the user can later be invited to file an upstream issue with a pre-filled bug-report URL.

manager_id: str¶

ID of the manager whose attribute was overridden.

field: str¶

Name of the overridden PackageManager attribute.

user_value: Any¶

Value the user supplied in their config file, after type coercion.

detected_cli_path: str | None¶

The CLI path mpm resolved with the built-in defaults, before the override took effect. None when mpm could not find the binary, which is itself a strong signal that the upstream search heuristics need help.

meta_package_manager.config.format_contribution_hints(hints)[source]¶

Render a multi-line, human-readable batch message inviting the user to contribute their overrides back upstream.

Returns an empty string for an empty list so the caller can branch on truthiness without a length check.

Return type:

str

meta_package_manager.config.validate_cooldown_section(section)[source]¶

Strict validator for the [mpm.cooldown] configuration sub-tree.

Delegates the shape and value checks to meta_package_manager.cooldown.parse_cooldown_section(), translating its ValueError into a click_extra.ValidationError. click-extra only hands dict sub-trees to extension validators, so the deprecated top-level string spelling never lands here: its migration warning is logged at runtime instead (see the mpm group body).

Raises:

click_extra.ValidationError – when the section is malformed.

Return type:

None

meta_package_manager.config.build_cooldown_validator()[source]¶

Construct a click_extra.ConfigValidator for the [mpm.cooldown] sub-tree.

Used by the CLI bootstrap (@group decorator) to register the validator alongside the manager-overrides one. Stateless: the cooldown section needs no pool binding, unlike the manager overrides.

Return type:

ConfigValidator

meta_package_manager.config.cooldown_section(ctx)[source]¶

Return the raw [mpm.cooldown] value from the loaded config, or None.

Reads the full parsed config click_extra exposes under CONF_FULL, tolerating a missing or malformed layer at each step: resolution decides how to read the value, and an invalid one already failed the load-time validator. The deprecated top-level string spelling comes through here unchanged.

Return type:

Any

meta_package_manager.config.validate_manager_overrides_section(section, *, pool)[source]¶

Strict validator for the [mpm.managers.<id>] configuration sub-tree.

Pure function: inspects section against the pool’s registered managers and OVERRIDABLE_FIELDS, raises the first click_extra.ValidationError it encounters, never mutates the pool. Suitable for registration as a click_extra.ConfigValidator and for direct invocation by apply_manager_overrides() so both the --validate-config path and the runtime application path enforce the same rules.

A section keyed by a built-in manager ID is validated as an override (its fields must be a subset of OVERRIDABLE_FIELDS). A section keyed by any other ID is validated as a brand-new manager definition via parse_manager_definition().

Raises:

click_extra.ValidationError – when section is not a mapping, an override sets an unknown field or a wrong-typed value, or a definition is malformed. The path of the raised error is relative to the [mpm.managers] section root (e.g. "winget.cli_searchpath"); click-extra prepends the app prefix when surfacing the error.

Return type:

None

meta_package_manager.config.apply_manager_overrides(pool, overrides)[source]¶

Apply per-manager attribute overrides parsed from the user’s config file.

Expects overrides to be a mapping of manager ID to a mapping of attribute name to its new value, as returned by conf["mpm"]["managers"]. None and empty mappings are accepted as no-op shortcuts so callers can unconditionally forward whatever was parsed from the config file.

Validation is delegated to validate_manager_overrides_section(), which raises click_extra.ValidationError on the first issue. Both the runtime config-loading path and the explicit --validate-config path enforce the same rules through that single validator, so a config that survives one survives the other.

After validation succeeds, every override is applied as an instance attribute (shadowing the class default for the lifetime of the process), recorded in overridden_fields so ManagerPool._select_managers() skips the matching global --<flag> defaults for that manager, and the cached properties derived from the affected attributes are evicted so the next access recomputes them. List-valued fields use replace semantics: the override fully supersedes the built-in default.

Returns a list of ContributionHint entries, one per accepted override that targets a CONTRIBUTION_HINT_FIELDS field. Each hint captures the pre-override cli_path so the contribution invitation can show what mpm would have detected without the user’s intervention.

Return type:

list[ContributionHint]

meta_package_manager.config.build_manager_overrides_validator(pool)[source]¶

Construct a click_extra.ConfigValidator for the [mpm.managers] sub-tree, bound to a specific ManagerPool.

Used by the CLI bootstrap (@group decorator) to register a validator against the live pool. Wrapping validate_manager_overrides_section() in a closure satisfies the click_extra.ConfigValidator.validator signature (Callable[[dict], None]) while keeping the underlying validator pool-agnostic and testable in isolation.

Return type:

ConfigValidator

meta_package_manager.config.dump_manager_overrides(manager)[source]¶

Return the current overridable attributes of manager as a TOML-ready dict.

Walks OVERRIDABLE_FIELDS in alphabetical order, reads each attribute from the manager instance, and converts tuples to lists so tomli_w can serialize the result without translation. Attributes whose value is None are skipped: TOML cannot express None and the user cannot override a field to None either, so emitting the key would be misleading.

Every other overridable field is emitted, including ones still at the class default. The output is meant to be a canonical override template: paste, prune the rows that don’t apply, and customize the rest.

Return type:

dict[str, Any]

meta_package_manager.config.CTX_HINTS_KEY: Final[str] = 'mpm.contribution_hints'¶

ctx.meta key under which collected ContributionHint entries are accumulated between apply_manager_overrides_from_context() and print_contribution_hints().

meta_package_manager.config.apply_manager_overrides_from_context(ctx, pool)[source]¶

Read the [mpm.managers.<id>] sections from the loaded config and apply them to pool.

Reads the full parsed config that click_extra exposes under CONF_FULL after configuration discovery and forwards the ["mpm"]["managers"] subtree to apply_manager_overrides(). Returns silently when no configuration file was loaded or when the section is absent.

Any ContributionHint returned by apply_manager_overrides() is stashed under CTX_HINTS_KEY for print_contribution_hints() to surface at the end of the run.

Return type:

None

meta_package_manager.config.print_contribution_hints(ctx)[source]¶

Print the collected contribution hints to <stderr>.

Reads from CTX_HINTS_KEY and writes via click_extra.echo() rather than the logging module, so the message survives --verbosity CRITICAL``and the``logging.disable() block that suppresses log output for serialization formats. Caller is expected to gate this on the user’s suggest_contribs preference.

Return type:

None

meta_package_manager.config.RISKY_OVERRIDE_FIELDS: Final[frozenset[str]] = frozenset({'cli_names', 'cli_search_path', 'pre_cmds', 'sudo'})¶

Override fields that can redirect mpm to run an arbitrary binary (or sudo).

When such an override is read from an untrusted config source, apply_manager_overrides_from_context() logs a warning. See docs/security.md.

meta_package_manager.config.config_file_is_trusted(path)[source]¶

Whether a config file is safe to load executable manager definitions from.

Trusted on POSIX when both the file and its parent directory are owned by the current user or root and are not group- or world-writable, mirroring how ssh, git and sudo reason about config-file trust: a writable file (or a writable directory that lets an attacker swap the file) could inject arbitrary commands.

On platforms without os.getuid (Windows), the POSIX ownership model does not apply and the check is skipped (returns True); see docs/security.md for the rationale and the residual risk.

Return type:

bool

meta_package_manager.config.register_config_managers(pool, definitions, *, source=None, source_is_url=False)[source]¶

Build and register config-defined managers into pool, applying the trust gate.

A definition is skipped (with a warning) when its ID collides with a built-in, when it comes from a remote URL config, or when its local config file fails config_file_is_trusted(). Returns the IDs actually registered. Definitions whose ID is already in the pool (e.g. registered by the eager pre-load) are silently skipped so the eager and callback passes are idempotent.

Return type:

list[str]

meta_package_manager.config.register_config_managers_from_context(ctx, pool)[source]¶

Register config-defined managers from the loaded config (authoritative pass).

Reads the parsed config under CONF_FULL, parses the non-built-in [mpm.managers.<id>] sections, and registers them through register_config_managers(). This is the source of truth for availability: a manager defined in a config the eager pre-load could not reach (a URL, a custom path) still works from here, it just does not get a dedicated CLI flag.

Return type:

None

meta_package_manager.config.discover_config_definitions(pool)[source]¶

Eagerly read new-manager definitions before the CLI group is built.

Best-effort and local-only: any error (no config, parse failure, missing reader) yields no definitions so CLI startup never breaks. URL configs are deferred to the authoritative register_config_managers_from_context() pass. Supports both the standalone [mpm.managers] layout and [tool.mpm.managers] in pyproject.toml.

Return type:

tuple[dict[str, ManagerDefinition], Path | None]

meta_package_manager.config.register_eager_config_managers(pool)[source]¶

Register config-defined managers before the CLI group is constructed.

Called from __main__.main() ahead of importing the Click group, so the dynamic --<id> / --no-<id> selectors enumerate the augmented pool and config-defined managers become first-class flags alongside the built-ins.

Return type:

None