zipremove 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zipremove
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Extend `zipfile` with `remove`-related functionalities
5
5
  Home-page: https://github.com/danny0838/zipremove
6
6
  Author: Danny Lin
@@ -10,6 +10,7 @@ Classifier: Development Status :: 4 - Beta
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: Topic :: System :: Archiving :: Compression
12
12
  Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
13
14
  Classifier: Programming Language :: Python :: 3.9
14
15
  Classifier: Programming Language :: Python :: 3.10
15
16
  Classifier: Programming Language :: Python :: 3.11
@@ -31,6 +32,12 @@ Requires-Dist: flake8-isort>=6.0; extra == "dev"
31
32
  Requires-Dist: isort>=5.5; extra == "dev"
32
33
  Dynamic: license-file
33
34
 
35
+ ![PyPI version](https://img.shields.io/pypi/v/zipremove.svg)
36
+ ![Python Versions](https://img.shields.io/pypi/pyversions/zipremove)
37
+ ![Status](https://img.shields.io/pypi/status/zipremove)
38
+ ![License](https://img.shields.io/github/license/danny0838/zipremove)
39
+ [![Downloads](https://static.pepy.tech/personalized-badge/zipremove?period=month&left_text=Downloads)](https://pepy.tech/project/zipremove)
40
+
34
41
  This package extends `zipfile` with `remove`-related functionalities.
35
42
 
36
43
  ## API
@@ -1,3 +1,9 @@
1
+ ![PyPI version](https://img.shields.io/pypi/v/zipremove.svg)
2
+ ![Python Versions](https://img.shields.io/pypi/pyversions/zipremove)
3
+ ![Status](https://img.shields.io/pypi/status/zipremove)
4
+ ![License](https://img.shields.io/github/license/danny0838/zipremove)
5
+ [![Downloads](https://static.pepy.tech/personalized-badge/zipremove?period=month&left_text=Downloads)](https://pepy.tech/project/zipremove)
6
+
1
7
  This package extends `zipfile` with `remove`-related functionalities.
2
8
 
3
9
  ## API
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = zipremove
3
- version = 0.2.0
3
+ version = 0.3.0
4
4
  author = Danny Lin
5
5
  author_email = danny0838@gmail.com
6
6
  url = https://github.com/danny0838/zipremove
@@ -13,6 +13,7 @@ classifiers =
13
13
  Intended Audience :: Developers
14
14
  Topic :: System :: Archiving :: Compression
15
15
  Programming Language :: Python :: 3
16
+ Programming Language :: Python :: 3 :: Only
16
17
  Programming Language :: Python :: 3.9
17
18
  Programming Language :: Python :: 3.10
18
19
  Programming Language :: Python :: 3.11
@@ -3,7 +3,9 @@ import io
3
3
  import os
4
4
  import struct
5
5
  from zipfile import *
6
- from zipfile import ( # noqa: F401
6
+ from zipfile import __all__ # noqa: F401
7
+ from zipfile import _get_compressor # noqa: F401
8
+ from zipfile import (
7
9
  _DD_SIGNATURE,
8
10
  _FH_COMPRESSED_SIZE,
9
11
  _FH_COMPRESSION_METHOD,
@@ -13,8 +15,6 @@ from zipfile import ( # noqa: F401
13
15
  _FH_GENERAL_PURPOSE_FLAG_BITS,
14
16
  _FH_SIGNATURE,
15
17
  _FH_UNCOMPRESSED_SIZE,
16
- LZMADecompressor,
17
- _get_compressor,
18
18
  _get_decompressor,
19
19
  crc32,
20
20
  sizeFileHeader,
@@ -49,6 +49,20 @@ except ImportError:
49
49
  filename = filename.replace(os.altsep, "/")
50
50
  return filename
51
51
 
52
+ try:
53
+ import zipfile
54
+ zipfile.LZMADecompressor().unused_data
55
+ except AttributeError:
56
+ # polyfill to support LZMADecompressor().unused_data
57
+ class LZMADecompressor(zipfile.LZMADecompressor):
58
+ @property
59
+ def unused_data(self):
60
+ try:
61
+ return self._decomp.unused_data
62
+ except AttributeError:
63
+ return b''
64
+ zipfile.LZMADecompressor = LZMADecompressor
65
+
52
66
 
53
67
  class _ZipRepacker:
54
68
  """Class for ZipFile repacking."""
@@ -471,11 +485,6 @@ class _ZipRepacker:
471
485
  if decompressor is None:
472
486
  return False
473
487
 
474
- # Current LZMADecompressor is unreliable since it's `.eof` is usually
475
- # not set as expected.
476
- if isinstance(decompressor, LZMADecompressor):
477
- return False
478
-
479
488
  dd_fmt = '<LQQ' if zip64 else '<LLL'
480
489
  dd_size = struct.calcsize(dd_fmt)
481
490
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zipremove
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Extend `zipfile` with `remove`-related functionalities
5
5
  Home-page: https://github.com/danny0838/zipremove
6
6
  Author: Danny Lin
@@ -10,6 +10,7 @@ Classifier: Development Status :: 4 - Beta
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: Topic :: System :: Archiving :: Compression
12
12
  Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
13
14
  Classifier: Programming Language :: Python :: 3.9
14
15
  Classifier: Programming Language :: Python :: 3.10
15
16
  Classifier: Programming Language :: Python :: 3.11
@@ -31,6 +32,12 @@ Requires-Dist: flake8-isort>=6.0; extra == "dev"
31
32
  Requires-Dist: isort>=5.5; extra == "dev"
32
33
  Dynamic: license-file
33
34
 
35
+ ![PyPI version](https://img.shields.io/pypi/v/zipremove.svg)
36
+ ![Python Versions](https://img.shields.io/pypi/pyversions/zipremove)
37
+ ![Status](https://img.shields.io/pypi/status/zipremove)
38
+ ![License](https://img.shields.io/github/license/danny0838/zipremove)
39
+ [![Downloads](https://static.pepy.tech/personalized-badge/zipremove?period=month&left_text=Downloads)](https://pepy.tech/project/zipremove)
40
+
34
41
  This package extends `zipfile` with `remove`-related functionalities.
35
42
 
36
43
  ## API
@@ -1623,50 +1623,51 @@ class ZipRepackerTests(unittest.TestCase):
1623
1623
 
1624
1624
  def test_scan_data_descriptor(self):
1625
1625
  repacker = zipfile._ZipRepacker()
1626
+ SIG = zipfile._DD_SIGNATURE
1626
1627
 
1627
1628
  # basic
1628
- bytes_ = b'dummyPK\x07\x08\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1629
+ bytes_ = b'dummy' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5)
1629
1630
  self.assertEqual(
1630
1631
  repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), False),
1631
1632
  (0x4ff4f23f, 5, 5, 16),
1632
1633
  )
1633
1634
 
1634
1635
  # return None if no signature
1635
- bytes_ = b'dummy\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1636
+ bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
1636
1637
  self.assertEqual(
1637
1638
  repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), False),
1638
1639
  None,
1639
1640
  )
1640
1641
 
1641
1642
  # return None if not unpackable
1642
- bytes_ = b'PK\x07\x08'
1643
+ bytes_ = struct.pack('<L', SIG)
1643
1644
  self.assertEqual(
1644
1645
  repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), False),
1645
1646
  None,
1646
1647
  )
1647
1648
 
1648
1649
  # return None if compressed size not match
1649
- bytes_ = b'dummPK\x07\x08\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1650
+ bytes_ = b'dumm' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5)
1650
1651
  self.assertEqual(
1651
1652
  repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), False),
1652
1653
  None,
1653
1654
  )
1654
1655
 
1655
1656
  # zip64
1656
- bytes_ = b'dummyPK\x07\x08\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00'
1657
+ bytes_ = b'dummy' + struct.pack('<2L2Q', SIG, 0x4ff4f23f, 5, 5)
1657
1658
  self.assertEqual(
1658
1659
  repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), True),
1659
1660
  (0x4ff4f23f, 5, 5, 24),
1660
1661
  )
1661
1662
 
1662
1663
  # offset
1663
- bytes_ = b'dummyPK\x07\x08\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1664
+ bytes_ = b'dummy' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5)
1664
1665
  self.assertEqual(
1665
1666
  repacker._scan_data_descriptor(io.BytesIO(bytes_), 1, len(bytes_), False),
1666
1667
  None,
1667
1668
  )
1668
1669
 
1669
- bytes_ = b'123dummyPK\x07\x08\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1670
+ bytes_ = b'123dummy' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5)
1670
1671
  self.assertEqual(
1671
1672
  repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_), False),
1672
1673
  None,
@@ -1677,13 +1678,13 @@ class ZipRepackerTests(unittest.TestCase):
1677
1678
  )
1678
1679
 
1679
1680
  # end_offset
1680
- bytes_ = b'dummyPK\x07\x08\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1681
+ bytes_ = b'dummy' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5)
1681
1682
  self.assertEqual(
1682
1683
  repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_) - 1, False),
1683
1684
  None,
1684
1685
  )
1685
1686
 
1686
- bytes_ = b'dummyPK\x07\x08\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00123'
1687
+ bytes_ = b'dummy' + struct.pack('<4L', SIG, 0x4ff4f23f, 5, 5) + b'123'
1687
1688
  self.assertEqual(
1688
1689
  repacker._scan_data_descriptor(io.BytesIO(bytes_), 0, len(bytes_) - 3, False),
1689
1690
  (0x4ff4f23f, 5, 5, 16),
@@ -1693,34 +1694,34 @@ class ZipRepackerTests(unittest.TestCase):
1693
1694
  repacker = zipfile._ZipRepacker()
1694
1695
 
1695
1696
  # basic
1696
- bytes_ = b'dummy\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1697
+ bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
1697
1698
  self.assertEqual(
1698
1699
  repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_), False),
1699
1700
  (0x4ff4f23f, 5, 5, 12),
1700
1701
  )
1701
1702
 
1702
1703
  # return None if compressed size not match
1703
- bytes_ = b'dumm\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1704
+ bytes_ = b'dumm' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
1704
1705
  self.assertEqual(
1705
1706
  repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_), False),
1706
1707
  None,
1707
1708
  )
1708
1709
 
1709
1710
  # zip64
1710
- bytes_ = b'dummy\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00'
1711
+ bytes_ = b'dummy' + struct.pack('<L2Q', 0x4ff4f23f, 5, 5)
1711
1712
  self.assertEqual(
1712
1713
  repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_), True),
1713
1714
  (0x4ff4f23f, 5, 5, 20),
1714
1715
  )
1715
1716
 
1716
1717
  # offset
1717
- bytes_ = b'dummy\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1718
+ bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
1718
1719
  self.assertEqual(
1719
1720
  repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 1, len(bytes_), False),
1720
1721
  None,
1721
1722
  )
1722
1723
 
1723
- bytes_ = b'123dummy\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1724
+ bytes_ = b'123dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
1724
1725
  self.assertEqual(
1725
1726
  repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_), False),
1726
1727
  None,
@@ -1731,20 +1732,20 @@ class ZipRepackerTests(unittest.TestCase):
1731
1732
  )
1732
1733
 
1733
1734
  # end_offset
1734
- bytes_ = b'dummy\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1735
+ bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
1735
1736
  self.assertEqual(
1736
1737
  repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_) - 1, False),
1737
1738
  None,
1738
1739
  )
1739
1740
 
1740
- bytes_ = b'dummy\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00123'
1741
+ bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5) + b'123'
1741
1742
  self.assertEqual(
1742
1743
  repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_) - 3, False),
1743
1744
  (0x4ff4f23f, 5, 5, 12),
1744
1745
  )
1745
1746
 
1746
1747
  # chunk_size
1747
- bytes_ = b'dummy\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1748
+ bytes_ = b'dummy' + struct.pack('<3L', 0x4ff4f23f, 5, 5)
1748
1749
  self.assertEqual(
1749
1750
  repacker._scan_data_descriptor_no_sig(io.BytesIO(bytes_), 0, len(bytes_), False, 12),
1750
1751
  (0x4ff4f23f, 5, 5, 12),
@@ -1767,7 +1768,7 @@ class ZipRepackerTests(unittest.TestCase):
1767
1768
 
1768
1769
  @requires_lzma()
1769
1770
  def test_scan_data_descriptor_no_sig_by_decompression_lzma(self):
1770
- self._test_scan_data_descriptor_no_sig_by_decompression_invalid(zipfile.ZIP_LZMA)
1771
+ self._test_scan_data_descriptor_no_sig_by_decompression(zipfile.ZIP_LZMA)
1771
1772
 
1772
1773
  @requires_zstd()
1773
1774
  def test_scan_data_descriptor_no_sig_by_decompression_zstd(self):
@@ -1782,27 +1783,34 @@ class ZipRepackerTests(unittest.TestCase):
1782
1783
 
1783
1784
  compressor = zipfile._get_compressor(method)
1784
1785
 
1785
- comp_bytes = compressor.compress(b'dummy')
1786
+ raw_bytes = b'dummy'
1787
+ raw_len = len(raw_bytes)
1788
+ comp_bytes = compressor.compress(raw_bytes)
1786
1789
  comp_bytes += compressor.flush()
1787
1790
  comp_len = len(comp_bytes)
1788
1791
 
1789
1792
  # basic
1790
- bytes_ = comp_bytes + b'\x3f\xf2\xf4\x4f' + struct.pack('<L', comp_len) + b'\x05\x00\x00\x00'
1793
+ bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)
1791
1794
  self.assertEqual(
1792
1795
  repacker._scan_data_descriptor_no_sig_by_decompression(
1793
1796
  io.BytesIO(bytes_), 0, len(bytes_), False, method),
1794
- (0x4ff4f23f, comp_len, 5, 12),
1797
+ (0x4ff4f23f, comp_len, raw_len, 12),
1795
1798
  )
1796
1799
 
1797
1800
  # return None if insufficient data length
1798
- bytes_ = b'\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00\x00'
1801
+ bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)
1799
1802
  self.assertEqual(
1800
1803
  repacker._scan_data_descriptor_no_sig_by_decompression(
1801
1804
  io.BytesIO(bytes_), 0, len(bytes_) - 1, False, method),
1802
1805
  None,
1803
1806
  )
1804
1807
 
1805
- bytes_ = b'\x3f\xf2\xf4\x4f\x05\x00\x00\x00\x05\x00\x00'
1808
+ bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)[:-1]
1809
+ self.assertEqual(
1810
+ repacker._scan_data_descriptor_no_sig_by_decompression(
1811
+ io.BytesIO(bytes_), 0, len(bytes_), False, method),
1812
+ None,
1813
+ )
1806
1814
  self.assertEqual(
1807
1815
  repacker._scan_data_descriptor_no_sig_by_decompression(
1808
1816
  io.BytesIO(bytes_), 0, len(bytes_) + 1, False, method),
@@ -1810,7 +1818,7 @@ class ZipRepackerTests(unittest.TestCase):
1810
1818
  )
1811
1819
 
1812
1820
  # return None if compressed size not match
1813
- bytes_ = comp_bytes + b'\x3f\xf2\xf4\x4f' + struct.pack('<L', comp_len - 1) + b'\x05\x00\x00\x00'
1821
+ bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len - 1, raw_len)
1814
1822
  self.assertEqual(
1815
1823
  repacker._scan_data_descriptor_no_sig_by_decompression(
1816
1824
  io.BytesIO(bytes_), 0, len(bytes_), False, method),
@@ -1818,41 +1826,41 @@ class ZipRepackerTests(unittest.TestCase):
1818
1826
  )
1819
1827
 
1820
1828
  # zip64
1821
- bytes_ = comp_bytes + b'\x3f\xf2\xf4\x4f' + struct.pack('<Q', comp_len) + b'\x05\x00\x00\x00\x00\x00\x00\x00'
1829
+ bytes_ = comp_bytes + struct.pack('<L2Q', 0x4ff4f23f, comp_len, raw_len)
1822
1830
  self.assertEqual(
1823
1831
  repacker._scan_data_descriptor_no_sig_by_decompression(
1824
1832
  io.BytesIO(bytes_), 0, len(bytes_), True, method),
1825
- (0x4ff4f23f, comp_len, 5, 20),
1833
+ (0x4ff4f23f, comp_len, raw_len, 20),
1826
1834
  )
1827
1835
 
1828
1836
  # offset
1829
- bytes_ = comp_bytes + b'\x3f\xf2\xf4\x4f' + struct.pack('<L', comp_len) + b'\x05\x00\x00\x00'
1837
+ bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)
1830
1838
  self.assertEqual(
1831
1839
  repacker._scan_data_descriptor_no_sig_by_decompression(
1832
1840
  io.BytesIO(bytes_), 1, len(bytes_), False, method),
1833
1841
  None,
1834
1842
  )
1835
1843
 
1836
- bytes_ = b'123' + comp_bytes + b'\x3f\xf2\xf4\x4f' + struct.pack('<L', comp_len) + b'\x05\x00\x00\x00'
1844
+ bytes_ = b'123' + comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)
1837
1845
  self.assertEqual(
1838
1846
  repacker._scan_data_descriptor_no_sig_by_decompression(
1839
1847
  io.BytesIO(bytes_), 3, len(bytes_), False, method),
1840
- (0x4ff4f23f, comp_len, 5, 12),
1848
+ (0x4ff4f23f, comp_len, raw_len, 12),
1841
1849
  )
1842
1850
 
1843
1851
  # end_offset
1844
- bytes_ = comp_bytes + b'\x3f\xf2\xf4\x4f' + struct.pack('<L', comp_len) + b'\x05\x00\x00\x00'
1852
+ bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len)
1845
1853
  self.assertEqual(
1846
1854
  repacker._scan_data_descriptor_no_sig_by_decompression(
1847
1855
  io.BytesIO(bytes_), 0, len(bytes_) - 2, False, method),
1848
1856
  None,
1849
1857
  )
1850
1858
 
1851
- bytes_ = comp_bytes + b'\x3f\xf2\xf4\x4f' + struct.pack('<L', comp_len) + b'\x05\x00\x00\x00123'
1859
+ bytes_ = comp_bytes + struct.pack('<3L', 0x4ff4f23f, comp_len, raw_len) + b'123'
1852
1860
  self.assertEqual(
1853
1861
  repacker._scan_data_descriptor_no_sig_by_decompression(
1854
1862
  io.BytesIO(bytes_), 0, len(bytes_) - 2, False, method),
1855
- (0x4ff4f23f, comp_len, 5, 12),
1863
+ (0x4ff4f23f, comp_len, raw_len, 12),
1856
1864
  )
1857
1865
 
1858
1866
  def _test_scan_data_descriptor_no_sig_by_decompression_invalid(self, method):
@@ -13,10 +13,10 @@ from .test_zipfile import struct_pack_no_dd_sig
13
13
 
14
14
  # polyfills
15
15
  try:
16
- from test.test_zipfile.test_core import Unseekable
16
+ from test.test_zipfile.test_core import Unseekable, requires_zlib
17
17
  except ImportError:
18
18
  # polyfill for Python < 3.12
19
- from test.test_zipfile import Unseekable
19
+ from test.test_zipfile import Unseekable, requires_zlib
20
20
 
21
21
  ENABLED_RESOURCES = set(os.environ.get("TEST_RESOURCES", "").split(","))
22
22
 
@@ -172,5 +172,39 @@ class TestRepack(unittest.TestCase):
172
172
  zh.repack()
173
173
  self.assertIsNone(zh.testzip())
174
174
 
175
+ @requires_zlib()
176
+ def test_strip_removed_large_file_with_dd_no_sig_by_decompression(self):
177
+ """Should scan for the data descriptor (without signature) of a removed
178
+ large file without causing a memory issue."""
179
+ # Try the temp file. If we do TESTFN2, then it hogs
180
+ # gigabytes of disk space for the duration of the test.
181
+ with TemporaryFile() as f:
182
+ tracemalloc.start()
183
+ self._test_strip_removed_large_file_with_dd_no_sig_by_decompression(
184
+ f, zipfile.ZIP_DEFLATED)
185
+ self.assertFalse(f.closed)
186
+ current, peak = tracemalloc.get_traced_memory()
187
+ tracemalloc.stop()
188
+ self.assertLess(peak, self.allowed_memory)
189
+
190
+ def _test_strip_removed_large_file_with_dd_no_sig_by_decompression(self, f, method):
191
+ file = 'file.txt'
192
+ file1 = 'largefile.txt'
193
+ data = b'Sed ut perspiciatis unde omnis iste natus error sit voluptatem'
194
+ with mock.patch('zipfile.struct.pack', side_effect=struct_pack_no_dd_sig):
195
+ with zipfile.ZipFile(Unseekable(f), 'w', compression=method) as zh:
196
+ with zh.open(file1, 'w', force_zip64=True) as fh:
197
+ self._write_large_file(fh)
198
+ zh.writestr(file, data)
199
+
200
+ with zipfile.ZipFile(f, 'a') as zh:
201
+ # make sure data descriptor bit is really set (by making zip file unseekable)
202
+ for zi in zh.infolist():
203
+ self.assertTrue(zi.flag_bits & 8, f'data descriptor flag not set: {zi.filename}')
204
+
205
+ zh.remove(file1)
206
+ zh.repack()
207
+ self.assertIsNone(zh.testzip())
208
+
175
209
  if __name__ == "__main__":
176
210
  unittest.main()
File without changes
File without changes
File without changes