meta_package_manager.package module¶
Manager-agnostic meta_package_manager.package.Package data model
and the meta_package_manager.package.PackageMetadata companion
that augments it with data pulled from sources outside the package manager
itself.
Defines the lightweight representation of a package (ID, name, installed and latest
versions, architecture) that every manager operation yields, plus
meta_package_manager.package.packages_asdict() to serialize a subset of its
fields for output.
Package is the inventory plane: what the package manager itself
reports through its native query commands. It backs every operation in
meta_package_manager.manager.
PackageMetadata is the enrichment plane:
licenses, supplier, checksums, declared dependency graph, on-disk per-package
SBOMs, and other facts gathered through extra queries (CLI sub-commands, on-disk
parsers, upstream registries). Populated by
meta_package_manager.manager.PackageManager.package_metadata_batch(),
consumed by meta_package_manager.sbom today and reserved for any
future caller that wants more than the bare inventory.
Kept deliberately free of manager logic, so it can be imported without pulling in the
manager engine (meta_package_manager.manager).
- meta_package_manager.package.PURL_QUALIFYING_NAMESPACES = frozenset({'alpm', 'apk', 'cpan', 'deb', 'luarocks', 'rpm'})¶
pURL types whose namespace qualifies a package without being part of its ID.
For these types, the namespace names who distributes the package: the vendor for
alpm,apk,debandrpm, the author’s CPAN ID forcpan, the user manifest forluarocks.parse_purl()keeps the name alone for them, where joining the two would askaptfordebian/curl. Every other type reads the namespace as the part of the package ID before its last slash: an npm scope, a Composer vendor, a Homebrew tap.Each type’s
namespace_definitionin the pURL type definitions settles which side it falls on.
- meta_package_manager.package.purl_parts(package_id)[source]¶
Split
package_idinto the namespace and the name of its pURL.Everything before the last slash is the namespace. The whole ID stays the name when the split would leave an empty segment, like an absolute path or a URL: a pURL parser drops empty segments, so the ID would not read back.
PURL_QUALIFYING_NAMESPACESplays no part here. A pURL mpm writes carries a manager ID as its type, and the managers whose ID is one of those types (apk,cpan,luarocks) never put a slash in a package ID, whichtests/test_docstring_corpus.pyholds across every documented package ID.
- meta_package_manager.package.manager_purl(manager_id, package_id, version=None)[source]¶
Render the pURL tying
package_idtomanager_id, the manager ID as its type.parse_purl()reads it back to the same manager ID, package ID and version, so a command handed this pURL skips looking the package up.Rendered here, not by packageurl-python’s
PackageURL.to_string(), which lowercases the name of some types, npm among them. The npm type definition keeps names case-sensitive, since packages published before 2015 may carry uppercase letters:JSONStreamwould come back asjsonstream.to_string()also leaves a/unencoded in a name (package-url/packageurl-python#123).Todo
Render with
PackageURL.to_string()once packageurl-python keeps the case of npm names (package-url/packageurl-python#230) and encodes a/in a name (package-url/packageurl-python#123).- Return type:
- meta_package_manager.package.purl_quote(text)[source]¶
Percent-encode one pURL segment, a
/included, keeping:as is.- Return type:
- class meta_package_manager.package.Package(id, manager_id, name=None, description=None, installed_version=None, latest_version=None, arch=None)[source]¶
Bases:
objectLightweight representation of a package and its metadata.
- manager_id: str¶
Handy to backtrack whose manager this package belongs to.
The manager ID is good enough and allows for no coupling with the parent manager object.
- name: str | None = None¶
Optional human-readable display name. Falls back to
idin output rendering, so only set this when the manager provides a name that differs from the package ID.
- installed_version: TokenizedString | str | None = None¶
- latest_version: TokenizedString | str | None = None¶
Installed and latest versions are optional: they’re not always provided by the package manager.
installed_versionandlatest_versionare allowed to temporarily be strings between__init__and__post_init__. Once they reach the later, they’re parsed and normalized into eitherTokenizedStringorNone. They can’t be strings beyond that point, i.e. after the Package instance has been fully instantiated. We don’t know how to declare this transient state with type hints, so we’re just going to allow string type.
- property purl: PackageURL[source]¶
Returns the package’s pURL object.
purl_parts()splits the ID, so a scoped npm package or a tap-qualified formula carries its namespace the way the pURL specification expects.
- static query_parts(query: str) frozenset[str][source]¶
Split
queryinto its contiguous alphanumeric segments.Contrary to
meta_package_manager.version.TokenizedString, does not split on collated number/alphabetic junctions.Canonical tokenizer behind
matches()and thesearch/installed/outdatedquery matching. Cached, since a run asks it the same question once per package of every manager.
- matches(query, extended=False, exact=False)[source]¶
Tell whether this package matches the free-form
query.Shared predicate behind the
search,installedandoutdatedsubcommands, so all three honor the same matching semantics:Fuzzy (default): a case-insensitive, tokenized substring match. Any alphanumeric segment of
query(seequery_parts()) found in the package ID or name counts as a match.Exact (
exact=True): the rawquerymust equal the package ID or name verbatim (case-sensitive, whole-string).Extended (
extended=True): also look into the packagedescription. Only meaningful when the description is populated, as it is forsearchresults.
A query with no alphanumeric segment (empty or punctuation-only) never matches.
- Return type:
- meta_package_manager.package.packages_asdict(packages, keep_fields)[source]¶
Yield each package as a
dictholding thekeep_fieldssubset of its fields.The fields are read straight off the instance rather than through
dataclasses.asdict(), which deep-copies every value: a version is an immutableTokenizedStringthat the renderers only read, and copying thousands of them per query cost more than the query’s own parsing.
- class meta_package_manager.package.DependencyScope(*values)[source]¶
-
Maps loosely onto SPDX
RelationshipTypevariants.SBOM renderers translate these into
RUNTIME_DEPENDENCY_OF,BUILD_DEPENDENCY_OF, etc.; CycloneDX collapses everything to its flatdependenciesgraph. Future non-SBOM consumers can apply their own mapping or just expose the raw scope label.- RUNTIME = 'runtime'¶
- BUILD = 'build'¶
- DEV = 'dev'¶
- OPTIONAL = 'optional'¶
- TEST = 'test'¶
- RECOMMENDED = 'recommended'¶
- class meta_package_manager.package.ChecksumAlgorithm(*values)[source]¶
-
Subset of algorithms shared by SPDX and CycloneDX schemas.
Used by
Checksumto identify a content hash without coupling the data model to any specific SBOM library’s enum.- MD5 = 'MD5'¶
- SHA1 = 'SHA1'¶
- SHA256 = 'SHA256'¶
- SHA512 = 'SHA512'¶
- SHA3_256 = 'SHA3-256'¶
- SHA3_512 = 'SHA3-512'¶
- BLAKE2B_256 = 'BLAKE2b-256'¶
- BLAKE2B_512 = 'BLAKE2b-512'¶
- class meta_package_manager.package.Checksum(algorithm, value)[source]¶
Bases:
objectA single
(algorithm, value)pair.- algorithm: ChecksumAlgorithm¶
- class meta_package_manager.package.Supplier(name, url=None)[source]¶
Bases:
objectDistributor of the package.
Distinct from the originator: the supplier is whoever served the bits (Homebrew, Debian, PyPI), the originator is the upstream author.
- class meta_package_manager.package.Originator(name, email=None, is_organization=False)[source]¶
Bases:
objectUpstream author or organization that produced the package.
- class meta_package_manager.package.Dependency(target_id, scope=DependencyScope.RUNTIME, version_constraint=None)[source]¶
Bases:
objectA single edge in the package’s declared dependency graph.
target_idis the dependency’s manager-native identifier (e.g.openssl@3for Homebrew). Renderers match it against the inventory’s installed packages to decide whether to emit a relationship.- scope: DependencyScope = 'runtime'¶
- class meta_package_manager.package.FileEntry(path, sha256=None, sha1=None, md5=None)[source]¶
Bases:
objectAn installed file shipped by the package.
Only populated for managers that can cheaply enumerate file contents and hashes (dpkg
.md5sums, pipRECORD). Omitted otherwise; the SBOM renderer leavesfilesAnalyzed=Falseon the SPDX Package.
- class meta_package_manager.package.PackageMetadata(download_url=None, homepage=None, vcs_url=None, issue_tracker_url=None, distribution_url=None, license_declared=None, license_concluded=None, copyright_text=None, supplier=None, originator=None, description=None, summary=None, cpe=None, dependencies=(), checksums=(), files=(), files_analyzed=False, install_date=None, build_date=None, release_date=None, external_sbom_path=None, extra_purls=(), extras=<factory>)[source]¶
Bases:
objectMaximalist metadata collected for a single installed package.
Distinct from
Packagein scope: wherePackagecarries only what the package manager itself surfaces through its inventory commands (id, name, version, arch),PackageMetadatacarries the augmentations gathered through extra queries (richer CLI sub-commands, on-disk parsing of dist-info or per-package SBOMs, upstream registry lookups). Today it powers the maximalistmpm sbom --bundledoutput; the structure is deliberately generic so a future search, audit, or info display can reuse it.All fields are optional.
extrasis the escape hatch for manager- native fields that don’t fit the portable model: a Homebrew tap, a pip classifier list, an aptSection. SBOM renderers consult known keys and surface the rest as CycloneDXproperties.- originator: Originator | None = None¶
- dependencies: tuple[Dependency, ...] = ()¶
- external_sbom_path: Path | None = None¶
Path to an on-disk upstream SBOM document for this package.
Brew formulae installed with
HOMEBREW_SBOM=1write a per-formula SPDX 2.3 file at<prefix>/sbom.spdx.json. The Homebrew extractor sets this so the SBOM renderer can merge the upstream document into the aggregate output (or attach it by reference).
- extra_purls: tuple[PackageURL, ...] = ()¶
Additional purls when the manager identifies the same package through multiple coordinate systems (multi-arch, multi-origin, or the upstream registry a recipe builds from).
SBOM renderers emit them as extra package-manager references and index them as aliases of the package’s own purl, so a vulnerability scan can query a coordinate an advisory database recognizes.
- meta_package_manager.package.EMPTY_METADATA = PackageMetadata(download_url=None, homepage=None, vcs_url=None, issue_tracker_url=None, distribution_url=None, license_declared=None, license_concluded=None, copyright_text=None, supplier=None, originator=None, description=None, summary=None, cpe=None, dependencies=(), checksums=(), files=(), files_analyzed=False, install_date=None, build_date=None, release_date=None, external_sbom_path=None, extra_purls=(), extras={})¶
Sentinel returned by the default no-op extractor on the base
meta_package_manager.manager.PackageManager. Consumers (the SBOM renderers today) treatEMPTY_METADATAexactly like--minimalmode for the package: no enrichment, no placeholders.