Skip to main content

multiarchive

A high level abstraction of multiple archive formats

Installation

uv add multiarchive

Optional dependency for RAR support:

uv add rarfile

ZStandard support requires the backports-zstd package on Python <3.14:

uv add "backports-zstd; python_version < '3.14'"

Quick Start

from multiarchive import Archive

# Open and inspect
with Archive("archive.zip") as arc:
    print(arc.namelist())  # list of member names
    print(len(arc))        # number of members
    print(arc.size)        # total uncompressed size in bytes

# Extract a single file
with Archive("archive.tar.gz") as arc:
    arc.extract("docs/readme.md", path="./output")

# Read file contents without extracting
with Archive("archive.zip") as arc:
    f = arc.open("config.json")
    content = f.read()
    f.close()

# Iterate over members
with Archive("archive.zip") as arc:
    for name in arc:
        if arc.is_file(name):
            print(f"  {name}")

Supported Formats

Format Read Write Extensions
ZIP Yes Yes .zip
TAR Yes Yes .tar
TAR.GZ Yes Yes .tgz, .tar.gz
TAR.BZ2 Yes Yes .tbz, .tbz2, .tar.bz2
TAR.XZ Yes Yes .tar.xz, .tar.lzma
TAR.ZST Yes Yes .tzst, .tar.zst
RAR Yes No .rar
GZIP Yes No .gz
BZIP2 Yes No .bz2
XZ Yes No .xz
ZSTD Yes No .zst, .zstd

RAR support requires the rarfile package and an external unrar tool. Plain compressed files expose one member named after the file without its compression extension (e.g. report.txt.gz contains report.txt). They support open() and extract(), but not writing or add(). Their infolist() entry has raw=None; calculating uncompressed size reads the compressed data.

Reading Archives

Opening

Use the context manager (recommended):

with Archive("file.zip") as arc:
    ...

Or the classmethod:

arc = Archive.open_archive("file.zip")
try:
    arc.namelist()
finally:
    arc.close()

Reading is supported on all formats If algo isnt explicitly provided, it will attempt to open it as ZIP first, then TAR, then RAR (if rarfile is installed). If all fails, it raises a ValueError.

Passwords

with Archive("file.zip", pwd=b"secret") as arc:
    ...

classmethod

arc = Archive.open_archive("file.zip", pwd=b"secret")

Exceptions for passwords:

  • ValueError: if archive needs password but none was provided
  • KeyError: if provided password is incorrect
  • TypeError: if password is provided for a tarball (not supported)

Listing Members

with Archive("file.zip") as arc:
    names = arc.namelist()  # Just names
    names = arc.members     # alias to namelist

    # extra info (ArchiveMemberInfo objects)
    for info in arc.infolist():
        print(f"{info.name}: {info.uncompressed_size} bytes, mtime={info.mtime}")

Checking Membership

with Archive("file.zip") as arc:
    if "config.json" in arc:
        print("Found!")

    for name in arc:
        if arc.is_file(name):
            ...
        if arc.is_dir(name):
            ...

Extracting

with Archive("file.tar.gz") as arc:
    # Single file
    arc.extract("src/main.py", path="./extracted")

Reading Member Contents

with Archive("file.zip") as arc:
    f = arc.open("data.json")
    if f is not None:
        content = f.read()
        f.close()

Writing Archives

Creating a New Archive

from multiarchive import Archive

# ZIP
with Archive("output.zip", mode="w") as arc:
    ...

# TAR.GZ with compression level
with Archive("output.tar.gz", mode="w", compression_level=9) as arc:
    ...

Add members with an optional name to use inside the archive:

with Archive("output.zip", mode="w") as arc:
    arc.add("src/main.py", arcname="main.py")

ZIP timestamps are limited to the years 1980 through 2107. To clamp timestamps outside that range instead of raising an error:

with Archive("output.zip", mode="w", strict_timestamps=False) as arc:
    arc.add("old-file.txt")

The format is determined by file extension. Use the algo parameter to override:

with Archive("my_archive", mode="w", algo="tar.xz") as arc:
    ...

Compression Levels

Format Range Default
ZIP 0–9 6
TAR.GZ 0–9 6
TAR.BZ2 1–9 9
TAR.XZ 0–9 6
TAR.ZST 1–22 3

File Information Object

The infolist() method returns ArchiveMemberInfo objects with a unified interface across all formats:

Field Type Description
name str Member filename
uncompressed_size int Original file size in bytes
compressed_size int | None Compressed size (None for TAR)
mtime float Modification time as epoch seconds
mode int | None Unix permission bits
is_dir bool Whether the member is a directory
raw ZipInfo | TarInfo | RarInfo | None Original backend object (None for plain compressed files)

Factory methods for direct conversion (you shouldn't need these in normal usage):

info = ArchiveMemberInfo.from_zipinfo(zip_info)
info = ArchiveMemberInfo.from_tarinfo(tar_info)
info = ArchiveMemberInfo.from_rarinfo(rar_info)

Properties

Method/Property Description
members Alias for namelist()
size Total uncompressed size of all members
comment / comment= Get/set archive comment (ZIP only, raises ValueError otherwise)

Error Handling

from multiarchive import Archive, BadArchiveError

try:
    with Archive("corrupted.zip") as arc:
        arc.namelist()
except BadArchiveError as e:
    print(f"Archive error: {e}")
except NotImplementedError as e:
    # password-protected (not supported)
    print(f"Not implemented: {e}")
except ValueError as e:
    # Unknown format
    print(f"Value error: {e}")
except FileNotFoundError:
    print("File not found")

API Reference

Archive

Archive(
    filename: str | Path,
    mode: str = "r",
    compression_level: int | None = None,
)
Parameter Description
filename Path to the archive file
mode 'r' for read, 'w' for write, 'a' for append
compression_level Compression level (format-dependent)

Methods

Method Description
open_archive(cls, filename, mode, compression_level) Factory method, returns opened archive
namelist() List of member names
infolist() List of ArchiveMemberInfo objects
extract(member, path) Extract single member
open(member, mode) Open member as file-like object
is_dir(member) Check if member is a directory
is_file(member) Check if member is a file
close() Explicitly close the archive

BadArchiveError

Raised when an archive file is corrupt or in an unsupported format.

ArchiveExtensions

Frozen dataclass mapping format names to their common file extensions:

ArchiveExtensions.zip     # (".zip",)
ArchiveExtensions.gz      # (".tgz", ".tar.gz")
ArchiveExtensions.xz      # (".tar.xz", ".tar.lzma")
# ... etc

Metadata

Release files for multiarchive 0.2.1

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

Source distribution (sdist)

Source distribution for multiarchive 0.2.1
File Size Uploaded Provenance Actions
multiarchive-0.2.1.tar.gz 11.6 kB Without provenance Details for multiarchive-0.2.1.tar.gz

Built distribution (wheel)

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

Total release size: 22.7 kB

Release files / multiarchive-0.2.1.tar.gz

Download URL multiarchive-0.2.1.tar.gz
Size 11.6 kB
Tags Source
SHA-256 checksum
How to use checksums
b1f67cfbac9716400f6d9ad95366233eb933aa57fcf3e75fc1d744a190bffe39
BLAKE2b-256 checksum
How to use checksums
757f265a0d68ef3f7c98b89888e28963b751c623393e2c4c8719155d47034256
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / multiarchive-0.2.1-py3-none-any.whl

Download URL multiarchive-0.2.1-py3-none-any.whl
Size 11.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
13a56877b5c51df71ec0ccba166939dcd61ede4b9589c27d20064135ccfdf2f5
BLAKE2b-256 checksum
How to use checksums
08095f8c8cc6ba817058ba57553a4ea675913ee738cf79d55394792836f5d068
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for multiarchive 0.2.1

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