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.1.tar.gz (98.7 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.1-cp310-abi3-win_amd64.whl (1.1 MB view details)

Uploaded CPython 3.10+Windows x86-64

rpmrepo_metadata-0.6.1-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.1-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.1-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.1.tar.gz.

File metadata

  • Download URL: rpmrepo_metadata-0.6.1.tar.gz
  • Upload date:
  • Size: 98.7 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.1.tar.gz
Algorithm Hash digest
SHA256 b380ce0fe17e4c68344ba05bafbf7e71a8eef43cdd555e59d1f502580d3820d8
MD5 fbc7eec26f92a8c68fcaf2f5055a7716
BLAKE2b-256 adb988fd7d1d12b1c647f08c71fac3a6344a1988ff67083629387d1e4444c9a0

See more details on using hashes here.

Provenance

The following attestation bundles were made for rpmrepo_metadata-0.6.1.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.1-cp310-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for rpmrepo_metadata-0.6.1-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 08f08d89a3562c406c73f911df3c3c5a93a1631c7faddd1a495e43c674241aeb
MD5 aedca389ff2df5ad1518dc2588e0939c
BLAKE2b-256 0aa3e20f5f2f80b50588a79ecb7e11332758b0ec7e7dc8f8c597c4b6e4a27bd7

See more details on using hashes here.

Provenance

The following attestation bundles were made for rpmrepo_metadata-0.6.1-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.1-cp310-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for rpmrepo_metadata-0.6.1-cp310-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ac7566136a4ba79a4c342da524cdad5f402adf752bb7b12728fbc37ebb9ac1eb
MD5 f25e697d168001c334900359c7fed012
BLAKE2b-256 0717162d35aa0107b519a1d05ab9aebbd8c3fee11a072e4078e0440ced507573

See more details on using hashes here.

Provenance

The following attestation bundles were made for rpmrepo_metadata-0.6.1-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.1-cp310-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for rpmrepo_metadata-0.6.1-cp310-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 d79cd6ccc0817f532221e5ad163efaa7131a5808cd6e29672656fb8e2960466a
MD5 bac6c0139c12450706bffda8c8e4672e
BLAKE2b-256 14081dcd15f04a25b7910adbc5ffd48dfd86eb9d514c399c74bf1f1364105a49

See more details on using hashes here.

Provenance

The following attestation bundles were made for rpmrepo_metadata-0.6.1-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.1-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rpmrepo_metadata-0.6.1-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a699c50ca02735888481d6581fc595dd979574eb65cc3ccc50dd87e34cf0c192
MD5 db4e09274c0ef671334ccfe6eaa04f9d
BLAKE2b-256 000f4441cb7eac9a8fcd7607a513349033e7e29f702e25f87a3001d8bd5c6212

See more details on using hashes here.

Provenance

The following attestation bundles were made for rpmrepo_metadata-0.6.1-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