CLI tool
miurahr/py7zr avatar
miurahr/py7zr

py7zr and reading 7z archives from Python

7zip in python3 with ZStandard, PPMd, LZMA2, LZMA1, Delta, BCJ, BZip2, and Deflate compressions, and AES encryption.

558 stars95 forksPythonLGPL-2.1

At a glance

What is it?
py7zr is a pure Python implementation of the 7z archive format, covering LZMA and LZMA2, BZip2, Deflate, ZStandard, Brotli and PPMd compression, 7zAES encryption and the Delta and BCJ filters, with a library API and a py7zr command line tool. The interesting constraint is that some of those algorithms are outside the 7z specification, so archives written with them are not readable by the original 7-Zip.
Who is it for?
py7zr is a good fit for a Python application that has to open 7z archives without shelling out to a 7-Zip binary, because it covers the compression methods and the 7zAES encryption that the format is actually used with, and it exposes both a library API and a command line tool.
Can I use it commercially?
Yes, with conditions. LGPL-2.1 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A 7z implementation in pure Python

py7zr is a library and utility to support 7zip archive compression, decompression, encryption and decryption, written in Python. The project description is more specific than that, listing the codecs: ZStandard, PPMd, LZMA2, LZMA1, Delta, BCJ, BZip2 and Deflate compressions, and AES encryption.

The primary language is Python and the pyproject.toml describes the package as a pure python 7-zip library. The licence is LGPL-2.1-or-later, and the homepage is the PyPI project page, with the project also distributed through conda-forge.

What makes the project worth a look is the codec coverage rather than the archive format itself. The 7z container is a fairly simple format, but the compression methods that go inside it are a mix of native library support and third-party bindings, and getting all of them to work in one pure Python package is the work. The README puts it plainly: py7zr supports algorithms and filters which the lzma module and liblzma support, and supports BZip2 and Deflate that are implemented in python core libraries, and it also supports ZStandard, Brotli and PPMd with third party libraries.

The audience is a Python developer who has to read or write 7z files. The common cases are a Windows-produced archive arriving on a Linux service, a build pipeline that standardises on 7z, and an application that reads archives a desktop tool produced. The alternative for all three is to shell out to the 7-Zip binary, which brings a platform dependency, an exit code to parse, and a subprocess boundary between your code and the data.

The project is not archived and the last push was on 2026-10-12, with the most recent releases being v1.1.4 on 2026-10-13, whose release note reads as fixing multiple vulnerabilities and bugs, v1.1.3 in June 2026 fixing multiple vulnerabilities, and v1.1.2 in January 2026 with a path sanitization update. That sequence of security releases in a single year is worth noting, since it speaks to the nature of the library.

The codec list, and what each one costs you

The supported algorithms are listed in three groups, and reading them together shows the shape of the library.

The compress group is LZMA2, LZMA, Bzip2, Deflate, Copy, ZStandard, Brotli, PPMd and Enhanced Deflate, which is marked experimental. The crypt group has one entry, 7zAES. The filters group has Delta and BCJ, with the branch variants X86, ARMT, ARM, PPC, SPARC and IA64.

The two that stand out as non-standard are ZStandard and Brotli. The README is explicit about the consequence: they are not default methods of 7-zip, so these archives are considered not to be compatible with original 7-zip on Windows or p7zip on Linux and Mac. Enhanced Deflate, also known as DEFLATE64, is a registered trademark of PKWARE, and it is tested only on CPython and disabled on PyPy.

That last note is the kind of detail that saves a debugging session. An archive that works on CPython and silently behaves differently on PyPy is a portability trap, and the README says so in the same breath as the codec list rather than leaving you to discover it.

The dependency list in pyproject.toml explains the implementation strategy. LZMA and LZMA2 come from the standard library's lzma module and liblzma. BZip2 and Deflate come from the Python core libraries. Everything else is a third-party binding: pyppmd for PPMd, pybcj for the BCJ branch filters, brotli on CPython and brotlicffi on PyPy, backports.zstd for Python versions before 3.14, inflate64 for Enhanced Deflate, and multivolumefile for multi-volume archives. Encryption comes from pycryptodomex, and psutil and texttable are also listed.

So the library is pure Python in the sense of being written in Python, but several of its codecs are still C extensions underneath. That is the honest characterisation, and it matters for portability: the package installs cleanly with wheels, but it is not dependency-free.

Reading and writing with SevenZipFile

The class API is the standard library shape, and the README gives two forms.

The explicit form opens the archive, extracts everything to a path, and closes it:

python
import py7zr

archive = py7zr.SevenZipFile('sample.7z', mode='r')
archive.extractall(path="/tmp")
archive.close()

And the context manager form, available since v0.6, is the one to reach for:

python
import py7zr

with py7zr.SevenZipFile('sample.7z', mode='r') as z:
    z.extractall()

with py7zr.SevenZipFile('target.7z', 'w') as z:
    z.writeall('./base_dir')

The context manager form is the better default for two reasons. It closes the archive even if extraction raises, and it is the shape that matches how the standard library treats file handles.

Selective extraction is supported through the extract method with a targets argument, and the README flags a specific failure mode: if you specify only a file but not a parent directory, it will fail. That is worth knowing before you write a selection routine, because the error message on a path miss may not obviously point at the missing parent.

The pattern for regex-based selection is also shown, compiling a pattern and using it against the archive:

python
import py7zr
import re

filter_pattern = re.compile(r'<your/target/file_and_directories/regex/expression>')
with py7zr.SevenZipFile('archive.7z

The incompatibility note in the README matters here. The methods read and readall were abandoned between v1.0.0-rc1 and v1.0.0-rc2. When you want to extract the archive to memory, you now use the extract method with a factory argument, and the factory takes a factory class, as of the GoF design pattern, that provides an object implementing the Py7zIO interface as a callback instance. The SevenZipFile extract and write methods put uncompressed data into your Py7zIO object.

That is the single most important API fact in the README for anyone upgrading from a pre-1.0 version, because it means in-memory extraction is no longer a method call but a callback contract, and existing code that reads into a BytesIO will need to be rewritten against the factory pattern.

The command line tool

The py7zr command line covers the operations you would expect, and the README lists them with examples.

Listing the contents of an archive is py7zr l test.7z. Extraction is py7zr x test.7z, and extraction with a password is py7zr x -P test.7z, which prompts for the password interactively.

Creating an archive is py7zr c target.7z test_dir, and creating a multi-volume archive adds the volume size flag, as in py7zr c -v 500k target.7z test_dir. Testing an archive is py7zr t test.7z, appending files to an existing archive is py7zr a test.7z test_dir, showing information is py7zr i, and the version is py7zr --version.

Two of these deserve comment. The test command is the one people tend to skip, and for a format with checksum verification per stream it is the cheapest way to know whether an archive is intact before you rely on it. And the multi-volume flag is more than a convenience, because 7z splits its own data streams across volumes in a way that a generic zip splitter cannot reproduce, so if you are producing volumes that other 7z tools will read, you need this rather than a manual split.

The tool is registered as a console script in pyproject.toml, mapping py7zr to py7zr.__main__:main, so it is installed alongside the library rather than being a separate download.

Installation is the ordinary one, either through pip:

bash
$ pip install py7zr

or through conda-forge:

bash
$ conda install -c conda-forge py7zr

The conda route is worth a mention for anyone who has hit wheel problems with the compression bindings, since conda-forge builds the native dependencies itself.

Compatibility boundaries, and where py7zr is not the answer

There are four limits stated in the README, and they are the ones to check before you commit to the library.

The first is BCJ2, which is listed under not supported algorithms, with the reason given as the standard lzma module not providing it. BCJ2 is a four-way parallel branch filter, and its absence is a real gap for anyone handling x86 executables where the BCJ2 variant is what the original tool produces.

The second is the ZStandard and Brotli compatibility point already mentioned. If you compress with those, the archive is readable by py7zr and by anything else built on py7zr, but not by the reference implementation.

The third is symbolic links. A feature handling symbolic links is basically compatible with the p7zip implementation but does not work with original 7-zip, because the original does not implement the feature. And py7zr tries checking symbolic links strictly and raises ValueError when a bad link is requested, but it does not guarantee to block all the bad cases.

That last sentence is the important one, and it is an admission of an incomplete defence. A ValueError is raised for the cases the library can detect, and the guarantee is explicitly not made for the rest. If your archive comes from an untrusted source and contains symlinks, the safe approach is to extract into a sandbox rather than relying on the check.

The fourth is the API break already described, the abandonment of read and readall in favour of the factory-based extract.

There is also a licensing consideration. The package is LGPL-2.1-or-later, which is a reasonable choice for a library that others might want to embed, and the project also carries a StandWithUkraine badge, a statement of the maintainer's position rather than a technical property of the code.

The alternative to py7zr is calling the 7-Zip binary through subprocess. The difference in approach is that py7zr gives you a Python API and in-process handling with no binary dependency, while the binary approach gives you guaranteed format compatibility with the reference implementation, including BCJ2, and costs you a subprocess per operation. For a service that occasionally needs to read an archive, py7zr is the better fit. For a system that must round-trip with 7-Zip exactly, the binary is safer.

Editorial conclusion

py7zr is a good fit for a Python application that has to open 7z archives without shelling out to a 7-Zip binary, because it covers the compression methods and the 7zAES encryption that the format is actually used with, and it exposes both a library API and a command line tool. It is a poor fit if you need archives that other tools can read and you have chosen ZStandard, Brotli or Enhanced Deflate, since those are not part of 7-Zip's own defaults, and a poor fit if you need BCJ2, which the library states it does not support. Before adopting, check which compression codec your existing archives use, and if you write new ones with ZStandard or Brotli, confirm with the consumers that they are also using py7zr rather than the reference implementation.

Frequently asked questions

Which compression algorithms does py7zr support?

LZMA2, LZMA, Bzip2, Deflate, Copy, ZStandard, Brotli, PPMd and Enhanced Deflate for compression, 7zAES for encryption, and the Delta and BCJ filters including the X86, ARMT, ARM, PPC, SPARC and IA64 variants.

How do I install py7zr?

With `pip install py7zr`, or with `conda install -c conda-forge py7zr` from conda-forge. The package requires Python 3.10 or later and supports CPython 3.10 through 3.14 as well as PyPy.

How do I extract a 7z archive in Python?

Open it with py7zr.SevenZipFile in mode r and call extractall, either with an explicit path or with no arguments, and use a with block so the archive is closed reliably. The context manager form has been available since v0.6.

Can I extract an archive into memory with py7zr?

Yes, through the extract method with a factory argument. The factory takes a factory class following the GoF design pattern that provides an object implementing the Py7zIO interface as a callback instance, into which SevenZipFile writes uncompressed data.

What does py7zr not support?

BCJ2 is not supported, because the standard lzma module does not provide it. Symbolic link handling is compatible with p7zip but not with original 7-zip, and ZStandard and Brotli archives are not compatible with the original 7-zip or p7zip tools.

What licence is py7zr released under?

LGPL-2.1-or-later, as declared in the project metadata. The most recent release is v1.1.4, dated 2026-10-13, with the release note referring to fixing multiple vulnerabilities and bugs.

Official sources

  1. License: LGPL-2.1
  2. miurahr/py7zr on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/miurahr-py7zr.svg)](https://hysenlabs.com/projects/miurahr-py7zr)

Was this useful?