Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-zipstream-ng for
openSUSE:Factory checked in at 2026-03-14 22:22:21
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-zipstream-ng (Old)
and /work/SRC/openSUSE:Factory/.python-zipstream-ng.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-zipstream-ng"
Sat Mar 14 22:22:21 2026 rev:4 rq:1338807 version:1.9.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-zipstream-ng/python-zipstream-ng.changes
2025-06-06 22:43:28.729853178 +0200
+++
/work/SRC/openSUSE:Factory/.python-zipstream-ng.new.8177/python-zipstream-ng.changes
2026-03-14 22:23:33.412017922 +0100
@@ -1,0 +2,6 @@
+Fri Mar 13 20:34:02 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 1.9.0:
+ * Add support for Zstandard compression where available (Python 3.14+)
+
+-------------------------------------------------------------------
Old:
----
zipstream_ng-1.8.0.tar.gz
New:
----
zipstream_ng-1.9.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-zipstream-ng.spec ++++++
--- /var/tmp/diff_new_pack.9iJjgd/_old 2026-03-14 22:23:33.972041122 +0100
+++ /var/tmp/diff_new_pack.9iJjgd/_new 2026-03-14 22:23:33.976041287 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-zipstream-ng
#
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
Name: python-zipstream-ng
-Version: 1.8.0
+Version: 1.9.0
Release: 0
Summary: Modern and easy to use streamable zip file generator
License: LGPL-3.0-only
++++++ zipstream_ng-1.8.0.tar.gz -> zipstream_ng-1.9.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zipstream_ng-1.8.0/PKG-INFO
new/zipstream_ng-1.9.0/PKG-INFO
--- old/zipstream_ng-1.8.0/PKG-INFO 2024-10-10 07:22:18.014251700 +0200
+++ new/zipstream_ng-1.9.0/PKG-INFO 2025-08-29 03:02:57.751773400 +0200
@@ -1,9 +1,9 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
Name: zipstream-ng
-Version: 1.8.0
+Version: 1.9.0
Summary: A modern and easy to use streamable zip file generator
Home-page: https://github.com/pR0Ps/zipstream-ng
-License: LGPLv3
+License: LGPL-3.0-only
Project-URL: Source, https://github.com/pR0Ps/zipstream-ng
Project-URL: Changelog,
https://github.com/pR0Ps/zipstream-ng/blob/master/CHANGELOG.md
Classifier: Programming Language :: Python :: 3
@@ -15,19 +15,30 @@
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
Classifier: Operating System :: OS Independent
Classifier: Topic :: System :: Archiving :: Compression
-Classifier: License :: OSI Approved :: GNU Lesser General Public License v3
(LGPLv3)
Requires-Python: >=3.5.0
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: tests
Requires-Dist: pytest; extra == "tests"
Requires-Dist: pytest-cov; extra == "tests"
+Dynamic: classifier
+Dynamic: description
+Dynamic: description-content-type
+Dynamic: home-page
+Dynamic: license
+Dynamic: license-file
+Dynamic: project-url
+Dynamic: provides-extra
+Dynamic: requires-python
+Dynamic: summary
zipstream-ng
============
-[](https://github.com/pR0Ps/zipstream-ng/actions/workflows/tests.yml)
+[](https://github.com/pR0Ps/zipstream-ng/actions/workflows/tests.yml?query=branch%3Amaster)
[](https://pypi.org/project/zipstream-ng/)

@@ -41,6 +52,7 @@
- Can calculate the total size of the resulting zip file before generation
even begins.
- Low memory usage: Since the zip is generated as it's requested, very little
has to be kept in
memory (peak usage of less than 20MB is typical, even for TBs of files).
+ - Performant: On-par or faster than using the standard library to create
non-streamed zip files.
- Flexible API: Typical use cases are simple, complicated ones are possible.
- Supports zipping data from files, bytes, strings, and any other iterable
objects.
- Keeps track of the date of the most recently modified file added to the zip
file.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zipstream_ng-1.8.0/README.md
new/zipstream_ng-1.9.0/README.md
--- old/zipstream_ng-1.8.0/README.md 2024-10-10 07:04:36.000000000 +0200
+++ new/zipstream_ng-1.9.0/README.md 2025-08-29 02:34:51.000000000 +0200
@@ -1,6 +1,6 @@
zipstream-ng
============
-[](https://github.com/pR0Ps/zipstream-ng/actions/workflows/tests.yml)
+[](https://github.com/pR0Ps/zipstream-ng/actions/workflows/tests.yml?query=branch%3Amaster)
[](https://pypi.org/project/zipstream-ng/)

@@ -14,6 +14,7 @@
- Can calculate the total size of the resulting zip file before generation
even begins.
- Low memory usage: Since the zip is generated as it's requested, very little
has to be kept in
memory (peak usage of less than 20MB is typical, even for TBs of files).
+ - Performant: On-par or faster than using the standard library to create
non-streamed zip files.
- Flexible API: Typical use cases are simple, complicated ones are possible.
- Supports zipping data from files, bytes, strings, and any other iterable
objects.
- Keeps track of the date of the most recently modified file added to the zip
file.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zipstream_ng-1.8.0/setup.py
new/zipstream_ng-1.9.0/setup.py
--- old/zipstream_ng-1.8.0/setup.py 2024-10-10 07:13:26.000000000 +0200
+++ new/zipstream_ng-1.9.0/setup.py 2025-08-29 03:01:42.000000000 +0200
@@ -14,7 +14,7 @@
setup(
name="zipstream-ng",
- version="1.8.0",
+ version="1.9.0",
description="A modern and easy to use streamable zip file generator",
long_description=long_description,
long_description_content_type="text/markdown",
@@ -23,7 +23,7 @@
"Source": "https://github.com/pR0Ps/zipstream-ng",
"Changelog":
"https://github.com/pR0Ps/zipstream-ng/blob/master/CHANGELOG.md",
},
- license="LGPLv3",
+ license="LGPL-3.0-only",
classifiers=[
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.5",
@@ -34,9 +34,10 @@
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
+ "Programming Language :: Python :: 3.13",
+ "Programming Language :: Python :: 3.14",
"Operating System :: OS Independent",
"Topic :: System :: Archiving :: Compression",
- "License :: OSI Approved :: GNU Lesser General Public License v3
(LGPLv3)"
],
packages=["zipstream"],
entry_points={
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zipstream_ng-1.8.0/tests/test_zipstream.py
new/zipstream_ng-1.9.0/tests/test_zipstream.py
--- old/zipstream_ng-1.8.0/tests/test_zipstream.py 2024-10-10
07:04:36.000000000 +0200
+++ new/zipstream_ng-1.9.0/tests/test_zipstream.py 2025-08-29
02:46:34.000000000 +0200
@@ -20,6 +20,7 @@
from zipstream import ZipStream
+PY313 = sys.version_info < (3, 14)
PY36 = sys.version_info < (3, 7)
PY35 = sys.version_info < (3, 6)
@@ -30,6 +31,14 @@
("mbyte", 1024 * 1024),
]
+COMPRESS_TYPES = [
+ zipfile.ZIP_STORED,
+ zipfile.ZIP_LZMA,
+ zipfile.ZIP_DEFLATED,
+ zipfile.ZIP_BZIP2,
+]
+if not PY313:
+ COMPRESS_TYPES.append(zipfile.ZIP_ZSTANDARD)
# Patch is_dir onto ZipInfo objects in 3.5 to make testing easier
@pytest.fixture(autouse=PY35)
@@ -107,12 +116,7 @@
# Tests start
################################
[email protected]("ct", [
- zipfile.ZIP_STORED,
- zipfile.ZIP_LZMA,
- zipfile.ZIP_DEFLATED,
- zipfile.ZIP_BZIP2
-])
[email protected]("ct", COMPRESS_TYPES)
def test_zipstream_compression(caplog, files, ct):
"""Test that all types of compression properly compress and extract"""
caplog.set_level(logging.WARNING)
@@ -135,12 +139,7 @@
_verify_zip_contains(zf, f)
[email protected]("ct", [
- zipfile.ZIP_STORED,
- zipfile.ZIP_LZMA,
- zipfile.ZIP_DEFLATED,
- zipfile.ZIP_BZIP2
-])
[email protected]("ct", COMPRESS_TYPES)
@pytest.mark.parametrize("cl", [None, 2])
def test_mixed_compression_and_getinfo(ct, cl):
"""Test that files are compressed using the correct method and level and
@@ -159,11 +158,14 @@
zs.add(b"3c", arcname="3c", compress_type=zipfile.ZIP_DEFLATED,
compress_level=TEST_CL)
zs.add(b"4", arcname="4", compress_type=zipfile.ZIP_BZIP2)
zs.add(b"4c", arcname="4c", compress_type=zipfile.ZIP_BZIP2,
compress_level=TEST_CL)
+ if not PY313:
+ zs.add(b"5", arcname="5", compress_type=zipfile.ZIP_ZSTANDARD)
+ zs.add(b"5c", arcname="5c", compress_type=zipfile.ZIP_ZSTANDARD,
compress_level=TEST_CL)
zf = _get_zip(zs)
zinfos = zf.infolist()
fullinfos = zs.info_list()
- assert len(zinfos) == len(fullinfos) == 9
+ assert len(zinfos) == len(fullinfos) == 9 + (0 if PY313 else 2)
def assert_zinfo(idx, name, compress_type, compress_level):
zi = zinfos[idx]
@@ -189,6 +191,9 @@
assert_zinfo(6, "3c", zipfile.ZIP_DEFLATED, TEST_CL)
assert_zinfo(7, "4", zipfile.ZIP_BZIP2, cl)
assert_zinfo(8, "4c", zipfile.ZIP_BZIP2, TEST_CL)
+ if not PY313:
+ assert_zinfo(9, "5", zipfile.ZIP_ZSTANDARD, cl)
+ assert_zinfo(10, "5c", zipfile.ZIP_ZSTANDARD, TEST_CL)
@pytest.mark.parametrize("zip64", [False, True])
@@ -368,6 +373,34 @@
zs.add(".", arcname=".", compress_type=ct)
[email protected](PY313, reason="Tests zstd compress_level (Python 3.14+
only)")
+def test_invalid_zstd_compression():
+ """Test zstd values outside of valid ones cause an error"""
+ ZipStream(compress_type=zipfile.ZIP_ZSTANDARD)
+
+ from compression.zstd import CompressionParameter
+ lower, upper = CompressionParameter.compression_level.bounds()
+
+ for x in (lower, lower+1, 0, upper-1, upper):
+ ZipStream(compress_type=zipfile.ZIP_ZSTANDARD, compress_level=x)
+
+ for x in (lower-1, upper+1):
+ with pytest.raises(ValueError):
+ ZipStream(compress_type=zipfile.ZIP_ZSTANDARD, compress_level=x)
+ with pytest.raises(ValueError):
+ ZipStream().add_path(".", compress_type=zipfile.ZIP_ZSTANDARD,
compress_level=x)
+ with pytest.raises(ValueError):
+ ZipStream().add(".", arcname=".",
compress_type=zipfile.ZIP_ZSTANDARD, compress_level=x)
+
+ zs = ZipStream(compress_type=zipfile.ZIP_ZSTANDARD)
+ with pytest.raises(ValueError):
+ zs.add(".", arcname=".", compress_level=x)
+
+ zs = ZipStream(compress_level=x)
+ with pytest.raises(ValueError):
+ zs.add(".", arcname=".", compress_type=zipfile.ZIP_ZSTANDARD)
+
+
def test_multibyte_and_non_ascii_characters_in_filenames():
zs = ZipStream(sized=True)
zs.add(None, "☆/")
@@ -734,12 +767,7 @@
[b"a", b"list", b"of", b"bytes"],
_gen_rand()
])
[email protected]("ct", [
- zipfile.ZIP_STORED,
- zipfile.ZIP_LZMA,
- zipfile.ZIP_DEFLATED,
- zipfile.ZIP_BZIP2
-])
[email protected]("ct", COMPRESS_TYPES)
def test_adding_data(caplog, data, ct):
"""Test adding non-files with different compression methods"""
caplog.set_level(logging.WARNING)
@@ -1173,6 +1201,36 @@
assert zinfos[0].date_time == (2107, 12, 31, 23, 59, 58)
[email protected](PY313, reason="Tests zstd compress_level (Python 3.14+
only)")
+def test_zstd_uses_compression_level():
+ """Test that the zstd compression level is applied"""
+ zs = ZipStream(compress_type=zipfile.ZIP_ZSTANDARD)
+ test = b"a"*1024
+ zs.add(test, "-7.txt", compress_level=-7)
+ zs.add(test, "default.txt")
+ zs.add(test, "22.txt", compress_level=22)
+
+ data = bytes(zs)
+ info = list(zs.info_list())
+ assert len(info) == zs.num_streamed() == 3
+
+ for x in info:
+ assert x["size"] == 1024
+ assert x["compress_type"] == zipfile.ZIP_ZSTANDARD
+ assert x["CRC"] == 2085984185
+
+ assert info[0]["name"] == "-7.txt"
+ assert info[1]["name"] == "default.txt"
+ assert info[2]["name"] == "22.txt"
+
+ # check compress level set
+ assert info[0]["compress_level"] == -7
+ assert info[1]["compress_level"] == None
+ assert info[2]["compress_level"] == 22
+
+ # check different compressed sizes for each level (in decreasing order as
level increases)
+ assert info[0]["compressed_size"] > info[1]["compressed_size"] >
info[2]["compressed_size"]
+
def test_info_list(monkeypatch):
faketime = (1980, 1, 1, 0, 0, 0)
@@ -1228,8 +1286,8 @@
assert len([x for x in info2 if not x["streamed"]]) == zs.num_queued() == 0
assert len([x for x in info2 if x["streamed"]]) == zs.num_streamed() == 3
- # Make sure any information that ws provided up-front hasn't changed
- # (except for the "streamed" key which mush got False -> True)
+ # Make sure any information that was provided up-front hasn't changed
+ # (except for the "streamed" key which must go False -> True)
for pre, post in zip(info, info2):
for k, v in pre.items():
if k == "streamed":
@@ -1525,6 +1583,9 @@
ZipStream(sized=True, compress_type=zipfile.ZIP_LZMA)
with pytest.raises(ValueError):
ZipStream(sized=True, compress_type=zipfile.ZIP_BZIP2)
+ if not PY313:
+ with pytest.raises(ValueError):
+ ZipStream(sized=True, compress_type=zipfile.ZIP_ZSTANDARD)
with pytest.raises(ValueError):
ZipStream.from_path(".", sized=True,
compress_type=zipfile.ZIP_DEFLATED)
@@ -1546,6 +1607,9 @@
szs.add("invalid", "invalid", compress_type=zipfile.ZIP_LZMA)
with pytest.raises(ValueError):
szs.add("invalid", "invalid", compress_type=zipfile.ZIP_BZIP2)
+ if not PY313:
+ with pytest.raises(ValueError):
+ szs.add("invalid", "invalid", compress_type=zipfile.ZIP_ZSTANDARD)
assert szs.sized
calculated = len(szs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zipstream_ng-1.8.0/zipstream/_async.py
new/zipstream_ng-1.9.0/zipstream/_async.py
--- old/zipstream_ng-1.8.0/zipstream/_async.py 1970-01-01 01:00:00.000000000
+0100
+++ new/zipstream_ng-1.9.0/zipstream/_async.py 2025-05-23 03:51:24.000000000
+0200
@@ -0,0 +1,96 @@
+
+
+__all__ += ["AsyncZipStream"]
+
+import asyncio
+try:
+ from asyncio import to_thread
+except ImportError:
+ # backport asyncio.to_thread from Python 3.9
+ from contextvars import copy_context
+ async def to_thread(func, /, *args, **kwargs):
+ loop = asyncio.get_running_loop()
+ return await loop.run_in_executor(
+ None,
+ functools.partial(copy_context().run, func, *args, **kwargs)
+ )
+
+async def _to_async_iter(it):
+ SENTINEL = object()
+ i = iter(it)
+ while True:
+ x = await to_thread(next, i, SENTINEL)
+ if x is SENTINEL:
+ break
+ yield x
+
+def _make_delegate_call(name):
+ @functools.wraps(getattr(ZipStream, name))
+ def method(self, *args, **kwargs):
+ return getattr(self._zip, name)(*args, **kwargs)
+ return method
+
+def _delegate(*fcns):
+ def cls_builder(cls):
+ for name in fcns:
+ setattr(cls, name, _make_delegate_call(name))
+ return cls
+ return cls_builder
+
+def _make_delegate_property(name):
+ return property(
+ fget=functools.wraps(getattr(ZipStream, name))(lambda s:
getattr(s._zip, name)),
+ fset=lambda s, v: setattr(s._zip, name, v)
+ )
+
+def _delegate_property(*fcns):
+ def cls_builder(cls):
+ for name in fcns:
+ setattr(cls, name, _make_delegate_property(name))
+ return cls
+ return cls_builder
+
+
+@_delegate("__len__", "__bool__", "__bytes__", "is_empty", "num_queued",
"num_streamed", "mkdir", "info_list")
+@_delegate_property("sized", "last_modified", "comment")
+class AsyncZipStream:
+ """An asynchronous write-only zip that is generated from source files/data
+ as it's asynchronously iterated over.
+
+ Ideal for situations where a zip file needs to be dynamically generated
+ without using temporary files (ie: web applications).
+
+ Implementation note: This class is an implementation of the synchronous
+ ZipStream class that delegates the work to a threadpool.
+ """
+
+ @functools.wraps(ZipStream.__init__)
+ def __init__(self, *args, **kwargs):
+ self._zip = ZipStream(*args, **kwargs)
+
+ async def __aiter__(self):
+ """Asynchronously generate zipped data from the added files/data"""
+ async for x in _to_async_iter(self._zip):
+ yield x
+
+ @classmethod
+ @functools.wraps(ZipStream.from_path)
+ async def from_path(cls, path, *, compress_type=ZIP_STORED,
compress_level=None, sized=None, **kwargs):
+ if sized is None:
+ sized = compress_type == ZIP_STORED
+
+ z = cls(
+ compress_type=compress_type,
+ compress_level=compress_level,
+ sized=sized
+ )
+ await z.add_path(path, **kwargs)
+ return z
+
+ @functools.wraps(ZipStream.add_path)
+ async def add_path(self, *args, **kwargs):
+ return await to_thread(self._zip.add_path, *args, **kwargs)
+
+ @functools.wraps(ZipStream.add)
+ async def add(self, data, *args, **kwargs):
+ return await to_thread(self._zip.add, data, *args, **kwargs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zipstream_ng-1.8.0/zipstream/ng.py
new/zipstream_ng-1.9.0/zipstream/ng.py
--- old/zipstream_ng-1.8.0/zipstream/ng.py 2024-10-10 07:04:36.000000000
+0200
+++ new/zipstream_ng-1.9.0/zipstream/ng.py 2025-08-29 02:46:34.000000000
+0200
@@ -33,6 +33,11 @@
)
+# Constants for compatibility modes
+PY313_COMPAT = sys.version_info < (3, 14) # disable zstd
+PY36_COMPAT = sys.version_info < (3, 7) # disable compress_level
+PY35_COMPAT = sys.version_info < (3, 6) # backport ZipInfo functions,
stringify path-like objects
+
# Size of chunks to read out of files
# Note that when compressing data the compressor will operate on bigger chunks
# than this - it keeps a cache as new chunks are fed to it.
@@ -51,16 +56,22 @@
# (includes "/" regardless of platform as per ZIP format specification)
PATH_SEPARATORS = set(x for x in (os.sep, os.altsep, "/") if x)
-# Constants for compatibility modes
-PY36_COMPAT = sys.version_info < (3, 7) # disable compress_level
-PY35_COMPAT = sys.version_info < (3, 6) # backport ZipInfo functions,
stringify path-like objects
+# zstd-related constants
+if not PY313_COMPAT:
+ from zipfile import ZIP_ZSTANDARD, ZSTANDARD_VERSION
+ from compression.zstd import CompressionParameter
+ ZSTD_LEVEL_BOUNDS = CompressionParameter.compression_level.bounds()
__all__ = [
# Defined classes
"ZipStream", "ZipStreamInfo",
# Compression constants (imported from zipfile)
- "ZIP_STORED", "ZIP_DEFLATED", "BZIP2_VERSION", "ZIP_BZIP2",
"LZMA_VERSION", "ZIP_LZMA",
+ "ZIP_STORED",
+ "ZIP_DEFLATED",
+ "ZIP_BZIP2", "BZIP2_VERSION",
+ "ZIP_LZMA", "LZMA_VERSION",
+ *(["ZIP_ZSTANDARD", "ZSTANDARD_VERSION"] if not PY313_COMPAT else []),
# Helper functions
"walk"
]
@@ -83,14 +94,34 @@
__log__.warning(
"compress_level has no effect when using ZIP_STORED/ZIP_LZMA"
)
- elif compress_type == ZIP_DEFLATED and not 0 <= compress_level <= 9:
- raise ValueError(
- "compress_level must be between 0 and 9 when using ZIP_DEFLATED"
- )
- elif compress_type == ZIP_BZIP2 and not 1 <= compress_level <= 9:
- raise ValueError(
- "compress_level must be between 1 and 9 when using ZIP_BZIP2"
- )
+ elif compress_type == ZIP_DEFLATED:
+ if not 0 <= compress_level <= 9:
+ raise ValueError(
+ "compress_level must be between 0 and 9 when using
ZIP_DEFLATED"
+ )
+ elif compress_type == ZIP_BZIP2:
+ if not 1 <= compress_level <= 9:
+ raise ValueError(
+ "compress_level must be between 1 and 9 when using ZIP_BZIP2"
+ )
+ elif not PY313_COMPAT and compress_type == ZIP_ZSTANDARD:
+ if not ZSTD_LEVEL_BOUNDS[0] <= compress_level <= ZSTD_LEVEL_BOUNDS[1]:
+ raise ValueError(
+ "compress_level must be between {} and {} when using
ZIP_ZSTANDARD".format(
+ *ZSTD_LEVEL_BOUNDS
+ )
+ )
+
+
+def _min_version_for_compress_type(compress_type, min_version=0):
+ """Ensure the compress_type is supported by the min_version"""
+ if compress_type == ZIP_BZIP2:
+ min_version = max(BZIP2_VERSION, min_version)
+ elif compress_type == ZIP_LZMA:
+ min_version = max(LZMA_VERSION, min_version)
+ elif not PY313_COMPAT and compress_type == ZIP_ZSTANDARD:
+ min_version = max(ZSTANDARD_VERSION, min_version)
+ return min_version
def _timestamp_to_dos(ts):
@@ -175,11 +206,7 @@
file_size = 0xFFFFFFFF
compress_size = 0xFFFFFFFF
- if self.compress_type == ZIP_BZIP2:
- min_version = max(BZIP2_VERSION, min_version)
- elif self.compress_type == ZIP_LZMA:
- min_version = max(LZMA_VERSION, min_version)
-
+ min_version = _min_version_for_compress_type(self.compress_type,
min_version)
self.extract_version = max(min_version, self.extract_version)
self.create_version = max(min_version, self.create_version)
filename, flag_bits = self._encodeFilenameFlags()
@@ -313,11 +340,7 @@
) + extra_data
min_version = ZIP64_VERSION
- if self.compress_type == ZIP_BZIP2:
- min_version = max(BZIP2_VERSION, min_version)
- elif self.compress_type == ZIP_LZMA:
- min_version = max(LZMA_VERSION, min_version)
-
+ min_version = _min_version_for_compress_type(self.compress_type,
min_version)
extract_version = max(min_version, self.extract_version)
create_version = max(min_version, self.create_version)
filename, flag_bits = self._encodeFilenameFlags()
@@ -338,7 +361,7 @@
len(filename),
len(extra_data),
len(self.comment),
- 0,
+ 0, # disk number this file begins on
self.internal_attr,
self.external_attr,
header_offset
@@ -500,19 +523,24 @@
compress_type:
The ZIP compression method to use when writing the archive, and
- should be ZIP_STORED, ZIP_DEFLATED, ZIP_BZIP2 or ZIP_LZMA;
- unrecognized values will cause NotImplementedError to be raised. If
- ZIP_DEFLATED, ZIP_BZIP2 or ZIP_LZMA is specified but the
- corresponding module (zlib, bz2 or lzma) is not available,
- RuntimeError is raised. The default is ZIP_STORED.
+ should be ZIP_STORED, ZIP_DEFLATED, ZIP_BZIP2, ZIP_LZMA, or
+ ZIP_ZSTANDARD (Python 3.14+); unrecognized values will cause
+ NotImplementedError to be raised.
+ If ZIP_DEFLATED, ZIP_BZIP2, ZIP_LZMA, or ZIP_ZSTANDARD is specified
+ but the corresponding module (zlib, bz2, lzma, or compression.zstd)
+ is not available, RuntimeError is raised. The default is
ZIP_STORED.
compress_level:
Controls the compression level to use when writing files to the
- archive. When using ZIP_STORED or ZIP_LZMA it has no effect. When
- using ZIP_DEFLATED integers 0 through 9 are accepted (see zlib for
- more information). When using ZIP_BZIP2 integers 1 through 9 are
- accepted (see bz2 for more information). Raises a ValueError if the
- provided value isn't valid for the `compress_type`.
+ archive. When using ZIP_STORED or ZIP_LZMA it has no effect.
+ When using ZIP_DEFLATED integers 0 through 9 are accepted (see zlib
+ for more information).
+ When using ZIP_BZIP2 integers 1 through 9 are accepted (see bz2 for
+ more information).
+ When using ZIP_ZSTANDARD integers -7 though 22 are common (see
+ compression.zstd.CompressionParameter for more information).
+ Raises a ValueError if the provided value isn't valid for the
+ `compress_type`.
Only available in Python 3.7+ (raises a ValueError if used on a
lower version)
@@ -1129,22 +1157,27 @@
centDirOffset > ZIP64_LIMIT or
centDirSize > ZIP64_LIMIT
):
- # Need to write the Zip64 end-of-archive records
+ # Need to also write a Zip64 end-of-archive record
zip64EndRec = struct.pack(
structEndArchive64,
stringEndArchive64,
- 44, 45, 45, 0, 0,
+ 44, # size of this record after this point
+ # (note: no "zip extensible data" is added so this is a
constant)
+ 45, # version made by (Zip64 support)
+ 45, # version needed to extract (Zip64 support)
+ 0, # disk number this record is on
+ 0, # disk number that contains the start of the central
directory
centDirCount,
centDirCount,
centDirSize,
- centDirOffset
+ centDirOffset,
)
zip64LocRec = struct.pack(
structEndArchive64Locator,
stringEndArchive64Locator,
- 0,
+ 0, # disk number where the zip64EndRec starts
zip64EndRecStart,
- 1
+ 1, # total number of disks
)
yield self._track(zip64EndRec + zip64LocRec)
@@ -1155,7 +1188,8 @@
endRec = struct.pack(
structEndArchive,
stringEndArchive,
- 0, 0,
+ 0, # disk number this record is on
+ 0, # disk number that contains the start of the central directory
centDirCount,
centDirCount,
centDirSize,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zipstream_ng-1.8.0/zipstream_ng.egg-info/PKG-INFO
new/zipstream_ng-1.9.0/zipstream_ng.egg-info/PKG-INFO
--- old/zipstream_ng-1.8.0/zipstream_ng.egg-info/PKG-INFO 2024-10-10
07:22:17.000000000 +0200
+++ new/zipstream_ng-1.9.0/zipstream_ng.egg-info/PKG-INFO 2025-08-29
03:02:57.000000000 +0200
@@ -1,9 +1,9 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
Name: zipstream-ng
-Version: 1.8.0
+Version: 1.9.0
Summary: A modern and easy to use streamable zip file generator
Home-page: https://github.com/pR0Ps/zipstream-ng
-License: LGPLv3
+License: LGPL-3.0-only
Project-URL: Source, https://github.com/pR0Ps/zipstream-ng
Project-URL: Changelog,
https://github.com/pR0Ps/zipstream-ng/blob/master/CHANGELOG.md
Classifier: Programming Language :: Python :: 3
@@ -15,19 +15,30 @@
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
Classifier: Operating System :: OS Independent
Classifier: Topic :: System :: Archiving :: Compression
-Classifier: License :: OSI Approved :: GNU Lesser General Public License v3
(LGPLv3)
Requires-Python: >=3.5.0
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: tests
Requires-Dist: pytest; extra == "tests"
Requires-Dist: pytest-cov; extra == "tests"
+Dynamic: classifier
+Dynamic: description
+Dynamic: description-content-type
+Dynamic: home-page
+Dynamic: license
+Dynamic: license-file
+Dynamic: project-url
+Dynamic: provides-extra
+Dynamic: requires-python
+Dynamic: summary
zipstream-ng
============
-[](https://github.com/pR0Ps/zipstream-ng/actions/workflows/tests.yml)
+[](https://github.com/pR0Ps/zipstream-ng/actions/workflows/tests.yml?query=branch%3Amaster)
[](https://pypi.org/project/zipstream-ng/)

@@ -41,6 +52,7 @@
- Can calculate the total size of the resulting zip file before generation
even begins.
- Low memory usage: Since the zip is generated as it's requested, very little
has to be kept in
memory (peak usage of less than 20MB is typical, even for TBs of files).
+ - Performant: On-par or faster than using the standard library to create
non-streamed zip files.
- Flexible API: Typical use cases are simple, complicated ones are possible.
- Supports zipping data from files, bytes, strings, and any other iterable
objects.
- Keeps track of the date of the most recently modified file added to the zip
file.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/zipstream_ng-1.8.0/zipstream_ng.egg-info/SOURCES.txt
new/zipstream_ng-1.9.0/zipstream_ng.egg-info/SOURCES.txt
--- old/zipstream_ng-1.8.0/zipstream_ng.egg-info/SOURCES.txt 2024-10-10
07:22:18.000000000 +0200
+++ new/zipstream_ng-1.9.0/zipstream_ng.egg-info/SOURCES.txt 2025-08-29
03:02:57.000000000 +0200
@@ -3,6 +3,7 @@
setup.py
tests/test_zipstream.py
zipstream/__init__.py
+zipstream/_async.py
zipstream/ng.py
zipstream/server.py
zipstream_ng.egg-info/PKG-INFO