@@ -1772,6 +1772,7 @@ def write(self, filename, arcname=None,
17721772 if zinfo .is_dir ():
17731773 zinfo .compress_size = 0
17741774 zinfo .CRC = 0
1775+ self .mkdir (zinfo )
17751776 else :
17761777 if compress_type is not None :
17771778 zinfo .compress_type = compress_type
@@ -1783,23 +1784,6 @@ def write(self, filename, arcname=None,
17831784 else :
17841785 zinfo ._compresslevel = self .compresslevel
17851786
1786- if zinfo .is_dir ():
1787- with self ._lock :
1788- if self ._seekable :
1789- self .fp .seek (self .start_dir )
1790- zinfo .header_offset = self .fp .tell () # Start of header bytes
1791- if zinfo .compress_type == ZIP_LZMA :
1792- # Compressed data includes an end-of-stream (EOS) marker
1793- zinfo .flag_bits |= _MASK_COMPRESS_OPTION_1
1794-
1795- self ._writecheck (zinfo )
1796- self ._didModify = True
1797-
1798- self .filelist .append (zinfo )
1799- self .NameToInfo [zinfo .filename ] = zinfo
1800- self .fp .write (zinfo .FileHeader (False ))
1801- self .start_dir = self .fp .tell ()
1802- else :
18031787 with open (filename , "rb" ) as src , self .open (zinfo , 'w' ) as dest :
18041788 shutil .copyfileobj (src , dest , 1024 * 8 )
18051789
@@ -1844,6 +1828,41 @@ def writestr(self, zinfo_or_arcname, data,
18441828 with self .open (zinfo , mode = 'w' ) as dest :
18451829 dest .write (data )
18461830
1831+ def mkdir (self , zinfo_or_directory_name , mode = 511 ):
1832+ """Creates a directory inside the zip archive."""
1833+ if isinstance (zinfo_or_directory_name , ZipInfo ):
1834+ zinfo = zinfo_or_directory_name
1835+ if not zinfo .is_dir ():
1836+ raise ValueError ("The given ZipInfo does not describe a directory" )
1837+ elif isinstance (zinfo_or_directory_name , str ):
1838+ directory_name = zinfo_or_directory_name
1839+ if not directory_name .endswith ("/" ):
1840+ directory_name += "/"
1841+ zinfo = ZipInfo (directory_name )
1842+ zinfo .compress_size = 0
1843+ zinfo .CRC = 0
1844+ zinfo .external_attr = ((0o40000 | mode ) & 0xFFFF ) << 16
1845+ zinfo .file_size = 0
1846+ zinfo .external_attr |= 0x10
1847+ else :
1848+ raise TypeError ("Expected type str or ZipInfo" )
1849+
1850+ with self ._lock :
1851+ if self ._seekable :
1852+ self .fp .seek (self .start_dir )
1853+ zinfo .header_offset = self .fp .tell () # Start of header bytes
1854+ if zinfo .compress_type == ZIP_LZMA :
1855+ # Compressed data includes an end-of-stream (EOS) marker
1856+ zinfo .flag_bits |= _MASK_COMPRESS_OPTION_1
1857+
1858+ self ._writecheck (zinfo )
1859+ self ._didModify = True
1860+
1861+ self .filelist .append (zinfo )
1862+ self .NameToInfo [zinfo .filename ] = zinfo
1863+ self .fp .write (zinfo .FileHeader (False ))
1864+ self .start_dir = self .fp .tell ()
1865+
18471866 def __del__ (self ):
18481867 """Call the "close()" method in case the user forgot."""
18491868 self .close ()
0 commit comments