Skip to main content

EZPI: a simple library to read and write public-inbox repos

This is a small library for reading and writing public-inbox v2 repositories. Note, that this is not a suitable replacement for public-inbox in itself – the goal is merely to provide a way to produce and consume public-inbox repositories that can be cloned, indexed and served from an actual public-inbox server running elsewhere.

What it does:

  • adds RFC2822 messages to git repositories compatible with public-inbox

  • supports public-inbox v2 format with automatic epoch management

  • reads messages out of a local public-inbox v2 repository using named cursors, with automatic rebase recovery

What it doesn’t do:

  • fetch, clone, or otherwise synchronize with remote repositories (use git, lei, or rsync for that)

  • parse messages (bytes in, bytes out)

  • anything else

For the public-inbox v2 format, see:

Requirements

The git command must exist and be in your path. Reading features that rely on rebase recovery need git 2.40 or newer for the --since-as-filter flag; ordinary reading and all writing work on any recent git.

Installing

For CLI usage, install with pipx:

pipx install ezpi

For library usage, install with pip:

pip install ezpi

Library usage

This is the simplest usage example:

from email.message import EmailMessage
from ezpi import add_rfc822_v2

msg = EmailMessage()
msg.set_content('Hello world!')
# We must have a Subject: and From: headers at least, in order
# to make a useful git commit with that data
msg['Subject'] = 'My excellent subject'
msg['From'] = 'E.X. Ample <example@example.com'>
# The v2 inbox will be created automatically if it doesn't exist
add_rfc822_v2('/path/to/inbox', msg)

You can also pass bytes instead of an EmailMessage object, but we must be able to run message_from_bytes() on it.

Reading a public-inbox repository

EZPI can also read messages out of a local v2 inbox that you’re keeping in sync yourself (via git pull, lei up, etc). Readers identify themselves with a cursor name; EZPI remembers per-cursor where each reader left off.

import ezpi

# First call seeds the cursor at HEAD and yields nothing.
for epoch, commit, msg_bytes in ezpi.iter_new_messages('/path/to/inbox', 'myapp'):
    pass

# After the repo is refreshed (git pull etc), new messages show up here.
# auto_advance=True persists cursor state after each yielded message.
for epoch, commit, msg_bytes in ezpi.iter_new_messages(
    '/path/to/inbox', 'myapp', auto_advance=True
):
    handle(msg_bytes)

# Backfill the whole history instead of starting at HEAD:
for epoch, commit, msg_bytes in ezpi.iter_new_messages(
    '/path/to/inbox', 'myapp', start='beginning'
):
    handle(msg_bytes)

New epochs are detected automatically on every call. If the repository history is rewritten to delete a message, EZPI detects the stale cursor and transparently relocates it by matching on Message-ID, Subject, and commit date.

ezpi command

We also provide an ezpi command. Example:

ezpi --v2-path /path/to/inbox --rfc822 < valid.eml

Run ezpi --help for full usage information.

How to delete messages?

Since every message is a separate commit to the git repository, deleting requires a git history rewrite. You will need to find the commit with the message you want to delete and perform operations directly on the git repository in order to delete that commit and rebase the ones that follow. Once it’s done, you will need to force-push the repository to wherever it is hosted.

Caution: if anyone is replicating your repository without –mirror, the history rewrite will result in an error the next time they do “git remote update”. Needless to say, they will be very interested in finding out what it is you just tried to delete, so use this as the last resort solution.

Support

For support or with any other questions, please email tools@kernel.org, or browse the list archive at https://lore.kernel.org/tools.

Please send patches to tools@kernel.org.

Submissions must be made under the terms of the Linux Foundation certificate of contribution and should include a Signed-off-by: line. Please read the DCO file for full legal definition of what that implies.

Metadata

Release files for ezpi 0.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ezpi 0.8.0
File Size Uploaded Provenance Actions
ezpi-0.8.0.tar.gz 50.1 kB Without provenance Details for ezpi-0.8.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ezpi 0.8.0
File Interpreter ABI Platform Actions
ezpi-0.8.0-py3-none-any.whl Python 3 none any Details for ezpi-0.8.0-py3-none-any.whl

Total release size: 72.1 kB

Release files / ezpi-0.8.0.tar.gz

Download URL ezpi-0.8.0.tar.gz
Size 50.1 kB
Tags Source
SHA-256 checksum
How to use checksums
dd6d6acd336ce1ab859f1af17ea41aeade6e4831ac45dc8302c860e6c10546aa
BLAKE2b-256 checksum
How to use checksums
c2fc66f11f007e4193ed268018ad79eb501dcf027df2ee279eb461811b1e05f8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.15.0

Release files / ezpi-0.8.0-py3-none-any.whl

Download URL ezpi-0.8.0-py3-none-any.whl
Size 22.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
15169c8fa8fbc9f97cb003264f3710f04071f4476ba90bdb86bafc97c2bc2d43
BLAKE2b-256 checksum
How to use checksums
49866623577e6d5da4b44cb6114480eb43b55e097ce651c4c926e0d7b4960e72
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.15.0

Security for ezpi 0.8.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page