Ticket #5766: zipstream-5766.patch

File zipstream-5766.patch, 15.1 KB (added by thijs, 2 years ago)
  • twisted/python/test/test_zipstream.py

     
    22# See LICENSE for details. 
    33 
    44""" 
    5 Tests for L{twisted.python.zipstream} 
     5Tests for L{twisted.python.zipstream}. 
    66""" 
     7 
    78import sys 
    89import random 
    910import zipfile 
     
    1112from twisted.python.compat import set 
    1213from twisted.python import zipstream, filepath 
    1314from twisted.python.hashlib import md5 
    14 from twisted.trial import unittest, util 
     15from twisted.trial import unittest 
     16 
    1517 
    1618class FileEntryMixin: 
    1719    """ 
    18     File entry classes should behave as file-like objects 
     20    File entry classes should behave as file-like objects. 
    1921    """ 
    2022    def getFileEntry(self, contents): 
    2123        """ 
     
    3133 
    3234    def test_isatty(self): 
    3335        """ 
    34         zip files should not be ttys, so isatty() should be false 
     36        zip files should not be ttys, so isatty() should be false. 
    3537        """ 
    3638        self.assertEqual(self.getFileEntry('').isatty(), False) 
    3739 
     
    122124 
    123125class DeflatedZipFileEntryTest(FileEntryMixin, unittest.TestCase): 
    124126    """ 
    125     DeflatedZipFileEntry should be file-like 
     127    DeflatedZipFileEntry should be file-like. 
    126128    """ 
    127129    compression = zipfile.ZIP_DEFLATED 
    128130 
     
    130132 
    131133class ZipFileEntryTest(FileEntryMixin, unittest.TestCase): 
    132134   """ 
    133    ZipFileEntry should be file-like 
     135   ZipFileEntry should be file-like. 
    134136   """ 
    135137   compression = zipfile.ZIP_STORED 
    136138 
     
    138140 
    139141class ZipstreamTest(unittest.TestCase): 
    140142    """ 
    141     Tests for twisted.python.zipstream 
     143    Tests for twisted.python.zipstream. 
    142144    """ 
    143145    def setUp(self): 
    144146        """ 
     
    167169        return zpfilename 
    168170 
    169171 
    170     def test_countEntries(self): 
    171         """ 
    172         Make sure the deprecated L{countZipFileEntries} returns the correct 
    173         number of entries for a zip file. 
    174         """ 
    175         name = self.makeZipFile(["one", "two", "three", "four", "five"]) 
    176         result = self.assertWarns(DeprecationWarning, 
    177                                   "countZipFileEntries is deprecated.", 
    178                                   __file__, lambda : 
    179                                       zipstream.countZipFileEntries(name)) 
    180         self.assertEqual(result, 5) 
    181  
    182  
    183172    def test_invalidMode(self): 
    184173        """ 
    185174        A ChunkingZipFile opened in write-mode should not allow .readfile(), 
     
    283272        self.assertEqual(czf.readfile("0").read(), "the real data") 
    284273 
    285274 
    286     def test_unzipIter(self): 
    287         """ 
    288         L{twisted.python.zipstream.unzipIter} should unzip a file for each 
    289         iteration and yield the number of files left to unzip after that 
    290         iteration 
    291         """ 
    292         numfiles = 10 
    293         contents = ['This is test file %d!' % i for i in range(numfiles)] 
    294         zpfilename = self.makeZipFile(contents) 
    295         uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path) 
    296         for i in range(numfiles): 
    297             self.assertEqual(len(list(self.unzipdir.children())), i) 
    298             self.assertEqual(uziter.next(), numfiles - i - 1) 
    299         self.assertEqual(len(list(self.unzipdir.children())), numfiles) 
    300  
    301         for child in self.unzipdir.children(): 
    302             num = int(child.basename()) 
    303             self.assertEqual(child.open().read(), contents[num]) 
    304     test_unzipIter.suppress = [ 
    305         util.suppress(message="zipstream.unzipIter is deprecated")] 
    306  
    307  
    308     def test_unzipIterDeprecated(self): 
    309         """ 
    310         Use of C{twisted.python.zipstream.unzipIter} will emit a 
    311         deprecated warning. 
    312         """ 
    313         zpfilename = self.makeZipFile('foo') 
    314  
    315         self.assertEqual(len(self.flushWarnings()), 0) 
    316  
    317         for f in zipstream.unzipIter(zpfilename, self.unzipdir.path): 
    318             pass 
    319  
    320         warnings = self.flushWarnings() 
    321         self.assertEqual(len(warnings), 1) 
    322         self.assertEqual(warnings[0]['category'], DeprecationWarning) 
    323         self.assertEqual( 
    324             warnings[0]['message'], 
    325             "zipstream.unzipIter is deprecated since Twisted 11.0.0 for " 
    326             "security reasons.  Use Python's zipfile instead.") 
    327  
    328  
    329275    def test_unzipIterChunky(self): 
    330276        """ 
    331277        L{twisted.python.zipstream.unzipIterChunky} returns an iterator which 
     
    363309            self.assertEqual(child.getContent(), contents[num]) 
    364310 
    365311 
    366     def test_unzip(self): 
    367         """ 
    368         L{twisted.python.zipstream.unzip} should extract all files from a zip 
    369         archive 
    370         """ 
    371         numfiles = 3 
    372         zpfilename = self.makeZipFile([str(i) for i in range(numfiles)]) 
    373         zipstream.unzip(zpfilename, self.unzipdir.path) 
    374         self.assertEqual( 
    375             set(self.unzipdir.listdir()), 
    376             set(map(str, range(numfiles)))) 
    377         for i in range(numfiles): 
    378             self.assertEqual(self.unzipdir.child(str(i)).getContent(), str(i)) 
    379     test_unzip.suppress = [ 
    380         util.suppress(message="zipstream.unzip is deprecated")] 
    381  
    382  
    383     def test_unzipDeprecated(self): 
    384         """ 
    385         Use of C{twisted.python.zipstream.unzip} will emit a deprecated warning. 
    386         """ 
    387         zpfilename = self.makeZipFile('foo') 
    388  
    389         self.assertEqual(len(self.flushWarnings()), 0) 
    390  
    391         zipstream.unzip(zpfilename, self.unzipdir.path) 
    392  
    393         warnings = self.flushWarnings() 
    394         self.assertEqual(len(warnings), 1) 
    395         self.assertEqual(warnings[0]['category'], DeprecationWarning) 
    396         self.assertEqual( 
    397             warnings[0]['message'], 
    398             "zipstream.unzip is deprecated since Twisted 11.0.0 for " 
    399             "security reasons.  Use Python's zipfile instead.") 
    400  
    401  
    402     def test_unzipDirectory(self): 
    403         """ 
    404         The path to which a file is extracted by L{zipstream.unzip} is 
    405         determined by joining the C{directory} argument to C{unzip} with the 
    406         path within the archive of the file being extracted. 
    407         """ 
    408         numfiles = 3 
    409         zpfilename = self.makeZipFile([str(i) for i in range(numfiles)], 'foo') 
    410         zipstream.unzip(zpfilename, self.unzipdir.path) 
    411         self.assertEqual( 
    412             set(self.unzipdir.child('foo').listdir()), 
    413             set(map(str, range(numfiles)))) 
    414         for i in range(numfiles): 
    415             self.assertEqual( 
    416                 self.unzipdir.child('foo').child(str(i)).getContent(), str(i)) 
    417     test_unzipDirectory.suppress = [ 
    418         util.suppress(message="zipstream.unzip is deprecated")] 
    419  
    420  
    421     def test_overwrite(self): 
    422         """ 
    423         L{twisted.python.zipstream.unzip} and 
    424         L{twisted.python.zipstream.unzipIter} shouldn't overwrite files unless 
    425         the 'overwrite' flag is passed 
    426         """ 
    427         testfile = self.unzipdir.child('0') 
    428         zpfilename = self.makeZipFile(['OVERWRITTEN']) 
    429  
    430         testfile.setContent('NOT OVERWRITTEN') 
    431         zipstream.unzip(zpfilename, self.unzipdir.path) 
    432         self.assertEqual(testfile.open().read(), 'NOT OVERWRITTEN') 
    433         zipstream.unzip(zpfilename, self.unzipdir.path, overwrite=True) 
    434         self.assertEqual(testfile.open().read(), 'OVERWRITTEN') 
    435  
    436         testfile.setContent('NOT OVERWRITTEN') 
    437         uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path) 
    438         uziter.next() 
    439         self.assertEqual(testfile.open().read(), 'NOT OVERWRITTEN') 
    440         uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path, 
    441                                      overwrite=True) 
    442         uziter.next() 
    443         self.assertEqual(testfile.open().read(), 'OVERWRITTEN') 
    444     test_overwrite.suppress = [ 
    445         util.suppress(message="zipstream.unzip is deprecated"), 
    446         util.suppress(message="zipstream.unzipIter is deprecated")] 
    447  
    448  
    449312    # XXX these tests are kind of gross and old, but I think unzipIterChunky is 
    450313    # kind of a gross function anyway.  We should really write an abstract 
    451314    # copyTo/moveTo that operates on FilePath and make sure ZipPath can support 
  • twisted/python/zipstream.py

     
    77bit of a file at a time, which means you can report progress as a file unzips. 
    88""" 
    99 
    10 import warnings 
    1110import zipfile 
    1211import os.path 
    1312import zlib 
    1413import struct 
    1514 
     15 
    1616_fileHeaderSize = struct.calcsize(zipfile.structFileHeader) 
    1717 
    1818class ChunkingZipFile(zipfile.ZipFile): 
    1919    """ 
    20     A ZipFile object which, with readfile(), also gives you access to a 
    21     filelike object for each entry. 
     20    A C{ZipFile} object which, with L{readfile}, also gives you access to a 
     21    file-like object for each entry. 
    2222    """ 
    2323 
    2424    def readfile(self, name): 
     
    6565    Abstract superclass of both compressed and uncompressed variants of 
    6666    file-like objects within a zip archive. 
    6767 
    68     @ivar chunkingZipFile: a chunking zip file. 
     68    @ivar chunkingZipFile: A chunking zip file. 
    6969    @type chunkingZipFile: L{ChunkingZipFile} 
    7070 
    7171    @ivar length: The number of bytes within the zip file that represent this 
    7272    file.  (This is the size on disk, not the number of decompressed bytes 
    7373    which will result from reading it.) 
    7474 
    75     @ivar fp: the underlying file object (that contains pkzip data).  Do not 
     75    @ivar fp: The underlying file object (that contains pkzip data).  Do not 
    7676    touch this, please.  It will quite likely move or go away. 
    7777 
    7878    @ivar closed: File-like 'closed' attribute; True before this file has been 
    7979    closed, False after. 
    80     @type closed: L{bool} 
     80    @type closed: C{bool} 
    8181 
    8282    @ivar finished: An older, broken synonym for 'closed'.  Do not touch this, 
    8383    please. 
    84     @type finished: L{int} 
     84    @type finished: C{int} 
    8585    """ 
    8686    def __init__(self, chunkingZipFile, length): 
    8787        """ 
     
    9696 
    9797    def isatty(self): 
    9898        """ 
    99         Returns false because zip files should not be ttys 
     99        Returns C{False} because zip files should not be ttys. 
    100100        """ 
    101101        return False 
    102102 
    103103 
    104104    def close(self): 
    105105        """ 
    106         Close self (file-like object) 
     106        Close self (file-like object). 
    107107        """ 
    108108        self.closed = True 
    109109        self.finished = 1 
     
    124124 
    125125    def next(self): 
    126126        """ 
    127         Implement next as file does (like readline, except raises StopIteration 
    128         at EOF) 
     127        Implement next as file does (like L{readline}, except raises 
     128        C{StopIteration} at EOF). 
    129129        """ 
    130130        nextline = self.readline() 
    131131        if nextline: 
     
    135135 
    136136    def readlines(self): 
    137137        """ 
    138         Returns a list of all the lines 
     138        Returns a list of all the lines. 
    139139        """ 
    140140        return list(self) 
    141141 
    142142 
    143143    def xreadlines(self): 
    144144        """ 
    145         Returns an iterator (so self) 
     145        Returns an iterator (so self). 
    146146        """ 
    147147        return self 
    148148 
    149149 
    150150    def __iter__(self): 
    151151        """ 
    152         Returns an iterator (so self) 
     152        Returns an iterator (so self). 
    153153        """ 
    154154        return self 
    155155 
     
    157157 
    158158class ZipFileEntry(_FileEntry): 
    159159    """ 
    160     File-like object used to read an uncompressed entry in a ZipFile 
     160    File-like object used to read an uncompressed entry in a C{ZipFile}. 
    161161    """ 
    162162 
    163163    def __init__(self, chunkingZipFile, length): 
     
    185185 
    186186class DeflatedZipFileEntry(_FileEntry): 
    187187    """ 
    188     File-like object used to read a deflated entry in a ZipFile 
     188    File-like object used to read a deflated entry in a C{ZipFile}. 
    189189    """ 
    190190 
    191191    def __init__(self, chunkingZipFile, length): 
     
    238238 
    239239 
    240240 
    241 def unzip(filename, directory=".", overwrite=0): 
    242     """ 
    243     Unzip the file 
    244  
    245     @param filename: the name of the zip file 
    246     @param directory: the directory into which the files will be 
    247     extracted 
    248     @param overwrite: if on, overwrite files when they exist.  You can 
    249     still get an error if you try to create a directory over a file 
    250     with the same name or vice-versa. 
    251     """ 
    252     warnings.warn("zipstream.unzip is deprecated since Twisted 11.0.0 for " + 
    253                   "security reasons.  Use Python's zipfile instead.", 
    254                   category=DeprecationWarning, stacklevel=2) 
    255  
    256     for i in unzipIter(filename, directory, overwrite, suppressWarning=True): 
    257         pass 
    258  
    259241DIR_BIT = 16 
    260242 
    261 def unzipIter(filename, directory='.', overwrite=0, suppressWarning=False): 
    262     """ 
    263     Return a generator for the zipfile.  This implementation will yield 
    264     after every file. 
    265  
    266     The value it yields is the number of files left to unzip. 
    267     """ 
    268     if not suppressWarning: 
    269         warnings.warn("zipstream.unzipIter is deprecated since Twisted " + 
    270                       "11.0.0 for security reasons.  Use Python's " + 
    271                       "zipfile instead.", 
    272                       category=DeprecationWarning, stacklevel=2) 
    273  
    274     zf = zipfile.ZipFile(filename, 'r') 
    275     names = zf.namelist() 
    276     if not os.path.exists(directory): 
    277         os.makedirs(directory) 
    278     remaining = len(zf.namelist()) 
    279     for entry in names: 
    280         remaining -= 1 
    281         isdir = zf.getinfo(entry).external_attr & DIR_BIT 
    282         f = os.path.join(directory, entry) 
    283         if isdir: 
    284             # overwrite flag only applies to files 
    285             if not os.path.exists(f): 
    286                 os.makedirs(f) 
    287         else: 
    288             # create the directory the file will be in first, 
    289             # since we can't guarantee it exists 
    290             fdir = os.path.split(f)[0] 
    291             if not os.path.exists(fdir): 
    292                 os.makedirs(fdir) 
    293             if overwrite or not os.path.exists(f): 
    294                 outfile = file(f, 'wb') 
    295                 outfile.write(zf.read(entry)) 
    296                 outfile.close() 
    297         yield remaining 
    298  
    299243 
    300244def countZipFileChunks(filename, chunksize): 
    301245    """ 
     
    311255 
    312256def countFileChunks(zipinfo, chunksize): 
    313257    """ 
    314     Count the number of chunks that will result from the given L{ZipInfo}. 
     258    Count the number of chunks that will result from the given C{ZipInfo}. 
    315259 
    316     @param zipinfo: a L{zipfile.ZipInfo} instance describing an entry in a zip 
     260    @param zipinfo: a C{zipfile.ZipInfo} instance describing an entry in a zip 
    317261    archive to be counted. 
    318262 
    319263    @return: the number of chunks present in the zip file.  (Even an empty file 
    320264    counts as one chunk.) 
    321     @rtype: L{int} 
     265    @rtype: C{int} 
    322266    """ 
    323267    count, extra = divmod(zipinfo.file_size, chunksize) 
    324268    if extra > 0: 
     
    326270    return count or 1 
    327271 
    328272 
    329 def countZipFileEntries(filename): 
    330     """ 
    331     Count the number of entries in a zip archive.  (Don't use this function.) 
    332  
    333     @param filename: The filename of a zip archive. 
    334     @type filename: L{str} 
    335     """ 
    336     warnings.warn("countZipFileEntries is deprecated.", 
    337                   DeprecationWarning, 2) 
    338     zf = zipfile.ZipFile(filename) 
    339     return len(zf.namelist()) 
    340  
    341273 
    342274def unzipIterChunky(filename, directory='.', overwrite=0, 
    343275                    chunksize=4096): 
  • twisted/topfiles/5766.removal

     
     1unzip, unzipIter, and countZipFileEntries in twisted.python.zipstream (deprecated in Twisted 11.0) are removed now.