meta_package_manager.specifier module¶

Utilities to manage and resolve constraints from a set of package specifiers.

meta_package_manager.specifier.VERSION_SEP: Final = '@'¶

Separator used by mpm to split package’s ID from its version:

This has been chosen as a separator because it is shared by popular package managers (like npm) and pURLs.

..code-block:

package_id@version
meta_package_manager.specifier.PURL_MAP: dict[str, set[str] | None] = {'alpine': None, 'alpm': {'pacaur', 'pacman', 'pamac', 'paru', 'yay'}, 'android': None, 'apache': None, 'apk': {'apk'}, 'bitbucket': None, 'bitnami': None, 'bower': None, 'buildroot': None, 'cargo': {'cargo'}, 'carthage': None, 'chef': None, 'chocolatey': {'choco'}, 'clojars': None, 'cocoapods': None, 'composer': {'composer'}, 'conan': None, 'conda': {'conda', 'pixi'}, 'coreos': None, 'cpan': {'cpan'}, 'cran': None, 'crystal': None, 'ctan': None, 'deb': {'apt', 'apt-mint'}, 'docker': None, 'drupal': None, 'dtype': None, 'dub': None, 'ebuild': {'emerge'}, 'eclipse': None, 'elm': None, 'gem': {'gem'}, 'generic': None, 'gitea': None, 'github': None, 'gitlab': None, 'golang': None, 'gradle': None, 'guix': {'guix'}, 'hackage': None, 'haxe': {'haxelib'}, 'helm': None, 'hex': None, 'huggingface': None, 'julia': None, 'luarocks': {'luarocks'}, 'maven': None, 'melpa': None, 'meteor': None, 'mlflow': None, 'nim': {'nimble'}, 'nix': {'nix'}, 'npm': {'bun', 'npm', 'pnpm', 'volta', 'yarn', 'yarn-berry'}, 'nuget': {'dotnet'}, 'oci': None, 'opam': None, 'openwrt': {'opkg'}, 'osgi': None, 'p2': None, 'pear': None, 'pecl': None, 'perl6': {'zef'}, 'platformio': None, 'pub': None, 'puppet': None, 'pypi': {'pip', 'pipx', 'uv'}, 'qpkg': None, 'rpm': {'dnf', 'dnf5', 'yum', 'zypper'}, 'rubygems': {'gem'}, 'sourceforge': None, 'sublime': None, 'swid': None, 'terraform': None, 'vagrant': None, 'vim': None, 'wordpress': None, 'yocto': None}¶

Map pURL’s types to MPM’s manager IDs.

Keys are recognized pURL’s types, and values are the set of MPM’s manager IDs that can handle the package type.

Warning

There is no official list of pkg:<type>/... prefixes defined in the pURL specification.

The only source we found lying around in the pURL literature is this list of diverse aliases, examples and libraries. We use this document to compile the keys of this PURL_MAP mapping.

Todo

Reuse the mapping that is proposed upstream to the package-url Python project.

class meta_package_manager.specifier.Specifier(raw_spec, package_id, manager_id=None, version=None)[source]¶

Bases: object

Lightweight representation of a package specification.

Contains all parsed metadata to be used as constraints.

raw_spec: str¶

Original, un-parsed specifier string provided by the user.

package_id: str¶

ID is required and is the primary key used for specification.

manager_id: str | None = None¶
version: str | None = None¶

Version string, a 1:1 copy of the one provided by the user.

classmethod parse_purl(spec_str)[source]¶

Resolve a pURL into its corresponding manager candidates.

Yields Specifier objects or returns None.

Return type:

tuple[Specifier, ...] | None

classmethod from_string(spec_str)[source]¶

Parse a string into a package specifier.

Supports various formats: - plain package_id - simple package ID with version: package_id@version - package with multiple version separators: @eslint/json@0.9.0 - pURL: pkg:npm/left-pad@3.7

If a specifier resolves to multiple constraints (as it might be the case for pURL), we produce and returns all variations. That way the Solver below has all necessary details to resolve the constraints.

Returns a tuple of Specifier.

Return type:

tuple[Specifier, ...]

property parsed_version: TokenizedString[source]¶
exception meta_package_manager.specifier.EmptyReduction[source]¶

Bases: Exception

Raised by the solver if no constraint can’t be met.

class meta_package_manager.specifier.Solver(spec_strings=None, manager_priority=None)[source]¶

Bases: object

Combine a set of Specifier and allow for the solving of the constraints they represent.

spec_pool: set[Specifier]¶
manager_priority: Sequence[str] = ()¶
populate_from_strings(spec_strings)[source]¶

Populate the solver with package specifiers parsed from provided strings.

top_priority_manager(keep_managers=None)[source]¶

Returns the top priority manager configured on the solver.

keep_managers allows for filtering by discarding managers not in that list.

Return type:

str | None

reduce_specs(specs)[source]¶

Reduce a collection of Specifier to its essential, minimal and unique form.

This method assumes that all provided specs are of the same package (like resolve_package_specs() does).

The reduction process consist of several steps. At each step, as soon as we managed to reduce the constraints to one Specifier, we returns it.

Filtering steps:

  1. We remove all constraints tied to all by the top priority manager if provided.

  2. If no manager priority is provided, we discard constraints not tied to a manager.

  3. We discard constraints not tied to a version.

  4. We only keep constraints tied to the highest version.

If we ends up with more than one set of constraints after all this filtering, an error is raised to invite the developer to troubleshoot the situation and refine this process.

Return type:

Specifier

resolve_package_specs()[source]¶

Regroup specs of the pool by package IDs, and solve their constraints.

Each package ID yields one reduced spec per distinct target manager. A package therefore produces several specs when the user explicitly names several managers for it (pkg:uv/rich pkg:brew/rich → one spec each). In contrast, a single alias pURL that expands to several managers (pkg:rpm/ping → dnf/yum/zypper) is a set of alternatives, reduced to the top-priority one.

Return type:

Iterator[tuple[str, Specifier]]

resolve_specs_group_by_managers()[source]¶

Resolves package specs, and returns them grouped by managers.

Return type:

dict[str | None, set[Specifier]]