Skip to main content

rpmrepo_metadata

PyPI Python

A Python library for reading, writing, and managing RPM repository metadata. Built on a Rust core for performance.

RPM repository metadata consists of several XML files — primary.xml, filelists.xml, other.xml, repomd.xml, updateinfo.xml, and comps.xml — that together describe the packages available in a repository. This library provides high-level APIs for working with all of these metadata types.

Installation

pip install rpmrepo_metadata

Requires Python >= 3.10. Pre-built wheels are available for Linux, macOS, and Windows.

Examples


Read a repository and iterate packages

Use RepositoryReader to stream through packages without loading everything into memory.

from rpmrepo_metadata import RepositoryReader

reader = RepositoryReader("path/to/repo/")

packages = reader.iter_packages()
print(f"Total packages: {packages.total_packages}")

for pkg in packages:
    print(f"{pkg.nevra()} - {pkg.summary}")
    print(f"  Size: {pkg.size_package} bytes")
    print(f"  Checksum: {pkg.checksum}")
    print(f"  Location: {pkg.location_href}")

Read advisories (updateinfo)

from rpmrepo_metadata import RepositoryReader

reader = RepositoryReader("path/to/repo/")

for advisory in reader.iter_advisories():
    print(f"[{advisory.update_type}] {advisory.id} - {advisory.title}")
    print(f"  Severity: {advisory.severity}")
    print(f"  Issued: {advisory.issued_date}")

    for ref in advisory.references:
        print(f"  {ref.reftype}: {ref.href}")

    for collection in advisory.pkglist:
        for pkg in collection.packages:
            print(f"  Package: {pkg.name}-{pkg.version}-{pkg.release}.{pkg.arch}")

Read comps data (groups, categories, environments)

from rpmrepo_metadata import RepositoryReader

reader = RepositoryReader("path/to/repo/")

comps = reader.read_comps()
if comps is not None:
    for group in comps.groups:
        print(f"Group: {group.name} ({group.id})")
        for pkg_req in group.packages:
            print(f"  {pkg_req.reqtype}: {pkg_req.name}")

    for category in comps.categories:
        print(f"Category: {category.name}")
        for group_id in category.group_ids:
            print(f"  Group: {group_id}")

    for env in comps.environments:
        print(f"Environment: {env.name} ({env.id})")
        for group_id in env.group_ids:
            print(f"  Group: {group_id}")
        for option in env.option_ids:
            print(f"  Optional: {option.group_id} (default={option.default})")

Create and populate a Package

from rpmrepo_metadata import Package

pkg = Package()
pkg.name = "my-package"
pkg.epoch = 0
pkg.version = "1.2.3"
pkg.release = "4.el9"
pkg.arch = "x86_64"

pkg.summary = "An example package"
pkg.description = "A longer description of the package"
pkg.url = "https://example.com"
pkg.rpm_license = "MIT"

pkg.checksum = ("sha256", "a" * 64)
pkg.location_href = "Packages/m/my-package-1.2.3-4.el9.x86_64.rpm"

pkg.size_package = 12345
pkg.size_installed = 67890
pkg.time_build = 1700000000

# Dependencies are tuples of (name, flags, epoch, version, release, preinstall)
pkg.requires = [
    ("glibc", "GE", "0", "2.17", "", False),
    ("bash", None, None, None, None, False),
]
pkg.provides = [("my-package", "EQ", "0", "1.2.3", "4.el9", False)]

# Files are tuples of (type, path) where type is None, "dir", or "ghost"
pkg.files = [
    (None, "/usr/bin/my-package"),
    ("dir", "/etc/my-package"),
]

# Changelogs are tuples of (author, timestamp, description)
pkg.changelogs = [
    ("John Doe <john@example.com>", 1700000000, "- Initial release"),
]

print(pkg.nevra())       # "my-package-0:1.2.3-4.el9.x86_64"
print(pkg.pkgid)          # "aaaa...aaaa"

Read an RPM file directly

Extract metadata from .rpm files on disk.

from rpmrepo_metadata import Package, ChecksumType

# Using defaults (SHA-256 checksum, 10 changelog entries)
pkg = Package.from_file("packages/foo-1.0-1.el9.x86_64.rpm")
print(f"{pkg.nevra()} - {len(pkg.files)} files")

# With custom options
pkg = Package.from_file_with_options(
    "packages/foo-1.0-1.el9.x86_64.rpm",
    checksum_type=ChecksumType.Sha512,
    location_href="Packages/f/foo-1.0-1.el9.x86_64.rpm",
    location_base="https://example.com/repo/",
    changelog_limit=5,
)
print(f"Checksum type: {pkg.checksum_type}")  # "sha512"
print(f"Location: {pkg.location_href}")

Write a repository with RepositoryWriter

Stream packages to disk one at a time, keeping memory usage low.

from rpmrepo_metadata import RepositoryWriter, Package

writer = RepositoryWriter("output/repo/", num_pkgs=100)

# Add packages
for rpm_path in rpm_files:
    pkg = Package.from_file(rpm_path)
    writer.add_package(pkg)

# Add advisories
advisory = UpdateRecord()
advisory.id = "EXAMPLE-2024:001"
advisory.title = "Important security fix"
advisory.update_type = "security"
advisory.severity = "Important"
writer.add_advisory(advisory)

# Finalize — writes repomd.xml and closes all files
writer.finish()

Work with Repository in-memory

Repository loads all metadata into memory, convenient for smaller repositories.

from rpmrepo_metadata import Repository

# Load from disk
repo = Repository.load_from_directory("path/to/repo/")

# Write to a new location
repo.write_to_directory("output/repo/")

Parse and compare EVR version strings

from rpmrepo_metadata import EVR

evr1 = EVR.parse("1:2.3.4-5.el9")
evr2 = EVR.parse("2.3.4-6.el9")

print(f"{evr1} vs {evr2}")
print(f"epoch={evr1.epoch}, version={evr1.version}, release={evr1.release}")

# Comparison operators
assert evr1 > evr2  # epoch 1 beats no epoch
assert EVR.parse("1.0-1") == EVR.parse("0:1.0-1")  # epoch 0 is the default
assert EVR.parse("1.0-2") > EVR.parse("1.0-1")

# Destructure into components
epoch, version, release = evr1.components()

Parse comps XML from a string

from rpmrepo_metadata import CompsData

xml = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE comps PUBLIC "-//Red Hat, Inc.//DTD Comps info//EN" "comps.dtd">
<comps>
  <group>
    <id>core</id>
    <name>Core</name>
    <description>Minimal system</description>
    <packagelist>
      <packagereq type="mandatory">bash</packagereq>
      <packagereq type="mandatory">coreutils</packagereq>
    </packagelist>
  </group>
</comps>"""

comps = CompsData.from_xml(xml)
print(f"{len(comps.groups)} groups")

# Serialize back to XML
output_xml = comps.to_xml()

Work with UpdateRecord (advisories)

from rpmrepo_metadata import (
    UpdateRecord, UpdateReference, UpdateCollection,
    UpdateCollectionPackage,
)

record = UpdateRecord()
record.id = "RHSA-2024:1234"
record.title = "Critical: kernel security update"
record.update_type = "security"
record.severity = "Critical"
record.issued_date = "2024-03-15"
record.summary = "An update for kernel is now available."
record.description = "The kernel packages contain the Linux kernel."

# Add a reference
ref = UpdateReference(
    href="https://bugzilla.redhat.com/show_bug.cgi?id=12345",
    id="12345",
    title="kernel vulnerability",
    reftype="bugzilla",
)
record.references = [ref]

# Add affected packages
pkg = UpdateCollectionPackage()
pkg.name = "kernel"
pkg.version = "5.14.0"
pkg.release = "362.24.1.el9_3"
pkg.arch = "x86_64"
pkg.epoch = "0"
pkg.filename = "kernel-5.14.0-362.24.1.el9_3.x86_64.rpm"

collection = UpdateCollection(name="Red Hat Enterprise Linux 9", shortname="RHEL-9")
collection.packages = [pkg]
record.pkglist = [collection]

Rust library

This package is built on a Rust library of the same name, also available on crates.io. See the Rust README and API documentation for Rust usage.

License

Mozilla Public License 2.0

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rpmrepo_metadata-0.6.0.tar.gz (98.3 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

rpmrepo_metadata-0.6.0-cp310-abi3-win_amd64.whl (1.1 MB view details)

Uploaded CPython 3.10+Windows x86-64

rpmrepo_metadata-0.6.0-cp310-abi3-manylinux_2_28_x86_64.whl (6.6 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.28+ x86-64

rpmrepo_metadata-0.6.0-cp310-abi3-manylinux_2_28_aarch64.whl (5.9 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.28+ ARM64

rpmrepo_metadata-0.6.0-cp310-abi3-macosx_11_0_arm64.whl (1.2 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

Details for the file rpmrepo_metadata-0.6.0.tar.gz.

File metadata

  • Download URL: rpmrepo_metadata-0.6.0.tar.gz
  • Upload date:
  • Size: 98.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for rpmrepo_metadata-0.6.0.tar.gz
Algorithm Hash digest
SHA256 8ca0eb325b2056ad05912670d5a5a75f4fc938098975831d68b162aa88692ba2
MD5 203f31a7bb03258637ca2afaee3fd787
BLAKE2b-256 5524adc609036c4aa0239d23a745e12ba41b40447afe096818158afb41e2fefb

See more details on using hashes here.

Provenance

The following attestation bundles were made for rpmrepo_metadata-0.6.0.tar.gz:

Publisher: release.yml on dralley/rpmrepo_metadata

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rpmrepo_metadata-0.6.0-cp310-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for rpmrepo_metadata-0.6.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 e2d76f54b87b27bed515bd204ac0ce5c4246d2c71c0a80bb2df079220543734a
MD5 560de4103759d7ac144f1cbb6b6622b6
BLAKE2b-256 c12bc10cf8a6e7ce3be5214e6a4d2a3f6b576786312cf3ca7b7ded7f30f66a80

See more details on using hashes here.

Provenance

The following attestation bundles were made for rpmrepo_metadata-0.6.0-cp310-abi3-win_amd64.whl:

Publisher: release.yml on dralley/rpmrepo_metadata

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rpmrepo_metadata-0.6.0-cp310-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for rpmrepo_metadata-0.6.0-cp310-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 f3397326674732356640aa46375c7bbf797b01ba4cd14015f9bc360bf271c08c
MD5 10cad24bf45219fdb2ddd0b505410271
BLAKE2b-256 8dad613a668d829ed9249142373edc571c08da3f76405dd6f713f2dfefba7ae8

See more details on using hashes here.

Provenance

The following attestation bundles were made for rpmrepo_metadata-0.6.0-cp310-abi3-manylinux_2_28_x86_64.whl:

Publisher: release.yml on dralley/rpmrepo_metadata

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rpmrepo_metadata-0.6.0-cp310-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for rpmrepo_metadata-0.6.0-cp310-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 82454ae14635f30333624a31387dd286e2ccc550f01c525e31d61f760cf4d931
MD5 2768fdabc5ca03ec83a87baadf7220ee
BLAKE2b-256 a00a070755f93f1ce2422904e89f1bcafe761ce27255ff977e0141342aaeb35b

See more details on using hashes here.

Provenance

The following attestation bundles were made for rpmrepo_metadata-0.6.0-cp310-abi3-manylinux_2_28_aarch64.whl:

Publisher: release.yml on dralley/rpmrepo_metadata

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rpmrepo_metadata-0.6.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rpmrepo_metadata-0.6.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 7972607b72401c209ea7ff04cd308894c23ee4734a67762a60ea90e8b78885cf
MD5 ac95aa5f544b07160625682ac86b915a
BLAKE2b-256 92b9ea4979eaeb6cda5c0cb7b4ccdb03ad1c6b81fcaf5e0c1af7026e2ad7de0c

See more details on using hashes here.

Provenance

The following attestation bundles were made for rpmrepo_metadata-0.6.0-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on dralley/rpmrepo_metadata

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page