Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add zlib-ng #135

Merged
merged 7 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,23 @@ jobs:
os: [ubuntu-latest]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.9"]
optional-deps: [true]
with-python-isal: [true]
with-libs: [true]
include:
- os: macos-latest
python-version: "3.10"
optional-deps: true
- os: ubuntu-20.04
python-version: "3.10"
with-python-isal: false
with-libs: false
optional-deps: false
- os: ubuntu-20.04
python-version: "3.10"
with-python-isal: false
with-libs: false
optional-deps: true
- os: ubuntu-20.04
python-version: "3.10"
optional-deps: false
with-python-isal: false
with-libs: false
with-zstandard: true
- os: windows-latest
python-version: "3.10"
Expand All @@ -77,10 +77,10 @@ jobs:
run: python -m pip install tox
- name: Test
run: tox -e py
if: matrix.with-python-isal
- name: Test without python-isal
run: tox -e no-isal
if: true && !matrix.with-python-isal
if: matrix.with-libs
- name: Test without python-isal and python-zlib-ng
run: tox -e no-libs
if: true && !matrix.with-libs
- name: Test with zstandard
if: matrix.with-zstandard
run: tox -e zstd
Expand Down
4 changes: 4 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ To ensure that you get the correct ``zstandard`` version, you can specify the ``
Changelog
---------

in-development
~~~~~~~~~~~~~~~~~~~
* #135: xopen now uses zlib-ng when available and applicable.

v1.8.0 (2023-11-03)
~~~~~~~~~~~~~~~~~~~
* #131: xopen now defers to the ``isal.igzip_threaded`` module rather than
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ classifiers = [
requires-python = ">=3.8"
dynamic = ["version"]
dependencies = [
'isal>=1.4.1; platform.machine == "x86_64" or platform.machine == "AMD64" or platform.machine == "aarch64"'
'isal>=1.4.1; platform.machine == "x86_64" or platform.machine == "AMD64" or platform.machine == "aarch64"',
'zlib-ng>=0.4.0; platform.machine == "x86_64" or platform.machine == "AMD64" or platform.machine == "aarch64"'
]

[project.urls]
Expand Down
47 changes: 46 additions & 1 deletion src/xopen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import subprocess
import tempfile
import time
import zlib
from abc import ABC, abstractmethod
from subprocess import Popen, PIPE, DEVNULL
from typing import (
Expand All @@ -57,6 +58,9 @@
igzip: Optional[ModuleType]
isal_zlib: Optional[ModuleType]
igzip_threaded: Optional[ModuleType]
zlib_ng: Optional[ModuleType]
gzip_ng: Optional[ModuleType]
gzip_ng_threaded: Optional[ModuleType]

try:
from isal import igzip, igzip_threaded, isal_zlib
Expand All @@ -65,6 +69,13 @@
isal_zlib = None
igzip_threaded = None

try:
from zlib_ng import gzip_ng, gzip_ng_threaded, zlib_ng
except ImportError:
gzip_ng = None
gzip_ng_threaded = None
zlib_ng = None

try:
import zstandard # type: ignore
except ImportError:
Expand Down Expand Up @@ -1062,6 +1073,27 @@ def _open_gz( # noqa: C901
)
except ValueError: # Wrong compression level
pass
if gzip_ng_threaded and zlib_ng and threads != 0:
try:
if compresslevel is None:
level = zlib_ng.Z_DEFAULT_COMPRESSION
elif compresslevel == 1:
# zlib-ng level 1 is 50% bigger than zlib level 1.
# This will be wildly outside user ballpark expectations, so
# increase the level
level = 2
else:
level = compresslevel

return gzip_ng_threaded.open(
filename,
mode,
level,
**text_mode_kwargs,
threads=1 if threads is None else threads,
)
except zlib_ng.error: # Bad compression level
pass
if threads != 0:
try:
if "r" in mode:
Expand All @@ -1078,6 +1110,8 @@ def _open_gz( # noqa: C901
if "r" in mode:
if igzip is not None:
return igzip.open(filename, mode, **text_mode_kwargs)
elif gzip_ng is not None:
return gzip_ng.open(filename, mode, **text_mode_kwargs)
return gzip.open(filename, mode, **text_mode_kwargs)

g = _open_reproducible_gzip(
Expand Down Expand Up @@ -1119,12 +1153,23 @@ def _open_reproducible_gzip(filename, mode, compresslevel):
except ValueError:
# Compression level not supported, move to built-in gzip.
pass
elif gzip_ng is not None:
if compresslevel == 1:
level = 2
elif compresslevel is None:
level = zlib_ng.Z_DEFAULT_COMPRESSION
else:
level = compresslevel
gzip_file = gzip_ng.GzipNGFile(**kwargs, compresslevel=level)

if gzip_file is None:
gzip_file = gzip.GzipFile(
**kwargs,
# Override gzip.open's default of 9 for consistency
# with command-line gzip.
compresslevel=6 if compresslevel is None else compresslevel,
compresslevel=zlib.Z_DEFAULT_COMPRESSION
if compresslevel is None
else compresslevel,
)
# When (I)GzipFile is created with a fileobj instead of a filename,
# the passed file object is not closed when (I)GzipFile.close()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_piped.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def test_concatenated_gzip_function():
)
def test_pipesize_changed(tmp_path, monkeypatch):
# Higher compression level to avoid opening with threaded opener
with xopen(tmp_path / "hello.gz", "wb", compresslevel=5) as f:
with PipedGzipWriter(tmp_path / "hello.gz", "wb", compresslevel=5) as f:
assert isinstance(f, PipedCompressionWriter)
assert fcntl.fcntl(f._file.fileno(), fcntl.F_GETPIPE_SZ) == _MAX_PIPE_SIZE

Expand Down
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ deps =
{[testenv]deps}
zstandard

[testenv:no-isal]
[testenv:no-libs]
commands=
pip uninstall -y isal
pip uninstall -y isal zlib-ng
{[testenv]commands}

[testenv:black]
Expand Down