PyXR

c:\python24\lib \ zipfile.py



0001 "Read and write ZIP files."
0002 
0003 import struct, os, time
0004 import binascii
0005 
0006 try:
0007     import zlib # We may need its compression method
0008 except ImportError:
0009     zlib = None
0010 
0011 __all__ = ["BadZipfile", "error", "ZIP_STORED", "ZIP_DEFLATED", "is_zipfile",
0012            "ZipInfo", "ZipFile", "PyZipFile"]
0013 
0014 class BadZipfile(Exception):
0015     pass
0016 error = BadZipfile      # The exception raised by this module
0017 
0018 # constants for Zip file compression methods
0019 ZIP_STORED = 0
0020 ZIP_DEFLATED = 8
0021 # Other ZIP compression methods not supported
0022 
0023 # Here are some struct module formats for reading headers
0024 structEndArchive = "<4s4H2lH"     # 9 items, end of archive, 22 bytes
0025 stringEndArchive = "PK\005\006"   # magic number for end of archive record
0026 structCentralDir = "<4s4B4HlLL5HLl"# 19 items, central directory, 46 bytes
0027 stringCentralDir = "PK\001\002"   # magic number for central directory
0028 structFileHeader = "<4s2B4HlLL2H"  # 12 items, file header record, 30 bytes
0029 stringFileHeader = "PK\003\004"   # magic number for file header
0030 
0031 # indexes of entries in the central directory structure
0032 _CD_SIGNATURE = 0
0033 _CD_CREATE_VERSION = 1
0034 _CD_CREATE_SYSTEM = 2
0035 _CD_EXTRACT_VERSION = 3
0036 _CD_EXTRACT_SYSTEM = 4                  # is this meaningful?
0037 _CD_FLAG_BITS = 5
0038 _CD_COMPRESS_TYPE = 6
0039 _CD_TIME = 7
0040 _CD_DATE = 8
0041 _CD_CRC = 9
0042 _CD_COMPRESSED_SIZE = 10
0043 _CD_UNCOMPRESSED_SIZE = 11
0044 _CD_FILENAME_LENGTH = 12
0045 _CD_EXTRA_FIELD_LENGTH = 13
0046 _CD_COMMENT_LENGTH = 14
0047 _CD_DISK_NUMBER_START = 15
0048 _CD_INTERNAL_FILE_ATTRIBUTES = 16
0049 _CD_EXTERNAL_FILE_ATTRIBUTES = 17
0050 _CD_LOCAL_HEADER_OFFSET = 18
0051 
0052 # indexes of entries in the local file header structure
0053 _FH_SIGNATURE = 0
0054 _FH_EXTRACT_VERSION = 1
0055 _FH_EXTRACT_SYSTEM = 2                  # is this meaningful?
0056 _FH_GENERAL_PURPOSE_FLAG_BITS = 3
0057 _FH_COMPRESSION_METHOD = 4
0058 _FH_LAST_MOD_TIME = 5
0059 _FH_LAST_MOD_DATE = 6
0060 _FH_CRC = 7
0061 _FH_COMPRESSED_SIZE = 8
0062 _FH_UNCOMPRESSED_SIZE = 9
0063 _FH_FILENAME_LENGTH = 10
0064 _FH_EXTRA_FIELD_LENGTH = 11
0065 
0066 def is_zipfile(filename):
0067     """Quickly see if file is a ZIP file by checking the magic number."""
0068     try:
0069         fpin = open(filename, "rb")
0070         endrec = _EndRecData(fpin)
0071         fpin.close()
0072         if endrec:
0073             return True                 # file has correct magic number
0074     except IOError:
0075         pass
0076     return False
0077 
0078 def _EndRecData(fpin):
0079     """Return data from the "End of Central Directory" record, or None.
0080 
0081     The data is a list of the nine items in the ZIP "End of central dir"
0082     record followed by a tenth item, the file seek offset of this record."""
0083     fpin.seek(-22, 2)               # Assume no archive comment.
0084     filesize = fpin.tell() + 22     # Get file size
0085     data = fpin.read()
0086     if data[0:4] == stringEndArchive and data[-2:] == "\000\000":
0087         endrec = struct.unpack(structEndArchive, data)
0088         endrec = list(endrec)
0089         endrec.append("")               # Append the archive comment
0090         endrec.append(filesize - 22)    # Append the record start offset
0091         return endrec
0092     # Search the last END_BLOCK bytes of the file for the record signature.
0093     # The comment is appended to the ZIP file and has a 16 bit length.
0094     # So the comment may be up to 64K long.  We limit the search for the
0095     # signature to a few Kbytes at the end of the file for efficiency.
0096     # also, the signature must not appear in the comment.
0097     END_BLOCK = min(filesize, 1024 * 4)
0098     fpin.seek(filesize - END_BLOCK, 0)
0099     data = fpin.read()
0100     start = data.rfind(stringEndArchive)
0101     if start >= 0:     # Correct signature string was found
0102         endrec = struct.unpack(structEndArchive, data[start:start+22])
0103         endrec = list(endrec)
0104         comment = data[start+22:]
0105         if endrec[7] == len(comment):     # Comment length checks out
0106             # Append the archive comment and start offset
0107             endrec.append(comment)
0108             endrec.append(filesize - END_BLOCK + start)
0109             return endrec
0110     return      # Error, return None
0111 
0112 
0113 class ZipInfo:
0114     """Class with attributes describing each file in the ZIP archive."""
0115 
0116     def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
0117         self.orig_filename = filename   # Original file name in archive
0118 # Terminate the file name at the first null byte.  Null bytes in file
0119 # names are used as tricks by viruses in archives.
0120         null_byte = filename.find(chr(0))
0121         if null_byte >= 0:
0122             filename = filename[0:null_byte]
0123 # This is used to ensure paths in generated ZIP files always use
0124 # forward slashes as the directory separator, as required by the
0125 # ZIP format specification.
0126         if os.sep != "/":
0127             filename = filename.replace(os.sep, "/")
0128         self.filename = filename        # Normalized file name
0129         self.date_time = date_time      # year, month, day, hour, min, sec
0130         # Standard values:
0131         self.compress_type = ZIP_STORED # Type of compression for the file
0132         self.comment = ""               # Comment for each file
0133         self.extra = ""                 # ZIP extra data
0134         self.create_system = 0          # System which created ZIP archive
0135         self.create_version = 20        # Version which created ZIP archive
0136         self.extract_version = 20       # Version needed to extract archive
0137         self.reserved = 0               # Must be zero
0138         self.flag_bits = 0              # ZIP flag bits
0139         self.volume = 0                 # Volume number of file header
0140         self.internal_attr = 0          # Internal attributes
0141         self.external_attr = 0          # External file attributes
0142         # Other attributes are set by class ZipFile:
0143         # header_offset         Byte offset to the file header
0144         # file_offset           Byte offset to the start of the file data
0145         # CRC                   CRC-32 of the uncompressed file
0146         # compress_size         Size of the compressed file
0147         # file_size             Size of the uncompressed file
0148 
0149     def FileHeader(self):
0150         """Return the per-file header as a string."""
0151         dt = self.date_time
0152         dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
0153         dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
0154         if self.flag_bits & 0x08:
0155             # Set these to zero because we write them after the file data
0156             CRC = compress_size = file_size = 0
0157         else:
0158             CRC = self.CRC
0159             compress_size = self.compress_size
0160             file_size = self.file_size
0161         header = struct.pack(structFileHeader, stringFileHeader,
0162                  self.extract_version, self.reserved, self.flag_bits,
0163                  self.compress_type, dostime, dosdate, CRC,
0164                  compress_size, file_size,
0165                  len(self.filename), len(self.extra))
0166         return header + self.filename + self.extra
0167 
0168 
0169 class ZipFile:
0170     """ Class with methods to open, read, write, close, list zip files.
0171 
0172     z = ZipFile(file, mode="r", compression=ZIP_STORED)
0173 
0174     file: Either the path to the file, or a file-like object.
0175           If it is a path, the file will be opened and closed by ZipFile.
0176     mode: The mode can be either read "r", write "w" or append "a".
0177     compression: ZIP_STORED (no compression) or ZIP_DEFLATED (requires zlib).
0178     """
0179 
0180     fp = None                   # Set here since __del__ checks it
0181 
0182     def __init__(self, file, mode="r", compression=ZIP_STORED):
0183         """Open the ZIP file with mode read "r", write "w" or append "a"."""
0184         if compression == ZIP_STORED:
0185             pass
0186         elif compression == ZIP_DEFLATED:
0187             if not zlib:
0188                 raise RuntimeError,\
0189                       "Compression requires the (missing) zlib module"
0190         else:
0191             raise RuntimeError, "That compression method is not supported"
0192         self.debug = 0  # Level of printing: 0 through 3
0193         self.NameToInfo = {}    # Find file info given name
0194         self.filelist = []      # List of ZipInfo instances for archive
0195         self.compression = compression  # Method of compression
0196         self.mode = key = mode[0]
0197 
0198         # Check if we were passed a file-like object
0199         if isinstance(file, basestring):
0200             self._filePassed = 0
0201             self.filename = file
0202             modeDict = {'r' : 'rb', 'w': 'wb', 'a' : 'r+b'}
0203             self.fp = open(file, modeDict[mode])
0204         else:
0205             self._filePassed = 1
0206             self.fp = file
0207             self.filename = getattr(file, 'name', None)
0208 
0209         if key == 'r':
0210             self._GetContents()
0211         elif key == 'w':
0212             pass
0213         elif key == 'a':
0214             try:                        # See if file is a zip file
0215                 self._RealGetContents()
0216                 # seek to start of directory and overwrite
0217                 self.fp.seek(self.start_dir, 0)
0218             except BadZipfile:          # file is not a zip file, just append
0219                 self.fp.seek(0, 2)
0220         else:
0221             if not self._filePassed:
0222                 self.fp.close()
0223                 self.fp = None
0224             raise RuntimeError, 'Mode must be "r", "w" or "a"'
0225 
0226     def _GetContents(self):
0227         """Read the directory, making sure we close the file if the format
0228         is bad."""
0229         try:
0230             self._RealGetContents()
0231         except BadZipfile:
0232             if not self._filePassed:
0233                 self.fp.close()
0234                 self.fp = None
0235             raise
0236 
0237     def _RealGetContents(self):
0238         """Read in the table of contents for the ZIP file."""
0239         fp = self.fp
0240         endrec = _EndRecData(fp)
0241         if not endrec:
0242             raise BadZipfile, "File is not a zip file"
0243         if self.debug > 1:
0244             print endrec
0245         size_cd = endrec[5]             # bytes in central directory
0246         offset_cd = endrec[6]   # offset of central directory
0247         self.comment = endrec[8]        # archive comment
0248         # endrec[9] is the offset of the "End of Central Dir" record
0249         x = endrec[9] - size_cd
0250         # "concat" is zero, unless zip was concatenated to another file
0251         concat = x - offset_cd
0252         if self.debug > 2:
0253             print "given, inferred, offset", offset_cd, x, concat
0254         # self.start_dir:  Position of start of central directory
0255         self.start_dir = offset_cd + concat
0256         fp.seek(self.start_dir, 0)
0257         total = 0
0258         while total < size_cd:
0259             centdir = fp.read(46)
0260             total = total + 46
0261             if centdir[0:4] != stringCentralDir:
0262                 raise BadZipfile, "Bad magic number for central directory"
0263             centdir = struct.unpack(structCentralDir, centdir)
0264             if self.debug > 2:
0265                 print centdir
0266             filename = fp.read(centdir[_CD_FILENAME_LENGTH])
0267             # Create ZipInfo instance to store file information
0268             x = ZipInfo(filename)
0269             x.extra = fp.read(centdir[_CD_EXTRA_FIELD_LENGTH])
0270             x.comment = fp.read(centdir[_CD_COMMENT_LENGTH])
0271             total = (total + centdir[_CD_FILENAME_LENGTH]
0272                      + centdir[_CD_EXTRA_FIELD_LENGTH]
0273                      + centdir[_CD_COMMENT_LENGTH])
0274             x.header_offset = centdir[_CD_LOCAL_HEADER_OFFSET] + concat
0275             # file_offset must be computed below...
0276             (x.create_version, x.create_system, x.extract_version, x.reserved,
0277                 x.flag_bits, x.compress_type, t, d,
0278                 x.CRC, x.compress_size, x.file_size) = centdir[1:12]
0279             x.volume, x.internal_attr, x.external_attr = centdir[15:18]
0280             # Convert date/time code to (year, month, day, hour, min, sec)
0281             x.date_time = ( (d>>9)+1980, (d>>5)&0xF, d&0x1F,
0282                                      t>>11, (t>>5)&0x3F, (t&0x1F) * 2 )
0283             self.filelist.append(x)
0284             self.NameToInfo[x.filename] = x
0285             if self.debug > 2:
0286                 print "total", total
0287         for data in self.filelist:
0288             fp.seek(data.header_offset, 0)
0289             fheader = fp.read(30)
0290             if fheader[0:4] != stringFileHeader:
0291                 raise BadZipfile, "Bad magic number for file header"
0292             fheader = struct.unpack(structFileHeader, fheader)
0293             # file_offset is computed here, since the extra field for
0294             # the central directory and for the local file header
0295             # refer to different fields, and they can have different
0296             # lengths
0297             data.file_offset = (data.header_offset + 30
0298                                 + fheader[_FH_FILENAME_LENGTH]
0299                                 + fheader[_FH_EXTRA_FIELD_LENGTH])
0300             fname = fp.read(fheader[_FH_FILENAME_LENGTH])
0301             if fname != data.orig_filename:
0302                 raise RuntimeError, \
0303                       'File name in directory "%s" and header "%s" differ.' % (
0304                           data.orig_filename, fname)
0305 
0306     def namelist(self):
0307         """Return a list of file names in the archive."""
0308         l = []
0309         for data in self.filelist:
0310             l.append(data.filename)
0311         return l
0312 
0313     def infolist(self):
0314         """Return a list of class ZipInfo instances for files in the
0315         archive."""
0316         return self.filelist
0317 
0318     def printdir(self):
0319         """Print a table of contents for the zip file."""
0320         print "%-46s %19s %12s" % ("File Name", "Modified    ", "Size")
0321         for zinfo in self.filelist:
0322             date = "%d-%02d-%02d %02d:%02d:%02d" % zinfo.date_time
0323             print "%-46s %s %12d" % (zinfo.filename, date, zinfo.file_size)
0324 
0325     def testzip(self):
0326         """Read all the files and check the CRC."""
0327         for zinfo in self.filelist:
0328             try:
0329                 self.read(zinfo.filename)       # Check CRC-32
0330             except BadZipfile:
0331                 return zinfo.filename
0332 
0333     def getinfo(self, name):
0334         """Return the instance of ZipInfo given 'name'."""
0335         return self.NameToInfo[name]
0336 
0337     def read(self, name):
0338         """Return file bytes (as a string) for name."""
0339         if self.mode not in ("r", "a"):
0340             raise RuntimeError, 'read() requires mode "r" or "a"'
0341         if not self.fp:
0342             raise RuntimeError, \
0343                   "Attempt to read ZIP archive that was already closed"
0344         zinfo = self.getinfo(name)
0345         filepos = self.fp.tell()
0346         self.fp.seek(zinfo.file_offset, 0)
0347         bytes = self.fp.read(zinfo.compress_size)
0348         self.fp.seek(filepos, 0)
0349         if zinfo.compress_type == ZIP_STORED:
0350             pass
0351         elif zinfo.compress_type == ZIP_DEFLATED:
0352             if not zlib:
0353                 raise RuntimeError, \
0354                       "De-compression requires the (missing) zlib module"
0355             # zlib compress/decompress code by Jeremy Hylton of CNRI
0356             dc = zlib.decompressobj(-15)
0357             bytes = dc.decompress(bytes)
0358             # need to feed in unused pad byte so that zlib won't choke
0359             ex = dc.decompress('Z') + dc.flush()
0360             if ex:
0361                 bytes = bytes + ex
0362         else:
0363             raise BadZipfile, \
0364                   "Unsupported compression method %d for file %s" % \
0365             (zinfo.compress_type, name)
0366         crc = binascii.crc32(bytes)
0367         if crc != zinfo.CRC:
0368             raise BadZipfile, "Bad CRC-32 for file %s" % name
0369         return bytes
0370 
0371     def _writecheck(self, zinfo):
0372         """Check for errors before writing a file to the archive."""
0373         if zinfo.filename in self.NameToInfo:
0374             if self.debug:      # Warning for duplicate names
0375                 print "Duplicate name:", zinfo.filename
0376         if self.mode not in ("w", "a"):
0377             raise RuntimeError, 'write() requires mode "w" or "a"'
0378         if not self.fp:
0379             raise RuntimeError, \
0380                   "Attempt to write ZIP archive that was already closed"
0381         if zinfo.compress_type == ZIP_DEFLATED and not zlib:
0382             raise RuntimeError, \
0383                   "Compression requires the (missing) zlib module"
0384         if zinfo.compress_type not in (ZIP_STORED, ZIP_DEFLATED):
0385             raise RuntimeError, \
0386                   "That compression method is not supported"
0387 
0388     def write(self, filename, arcname=None, compress_type=None):
0389         """Put the bytes from filename into the archive under the name
0390         arcname."""
0391         st = os.stat(filename)
0392         mtime = time.localtime(st.st_mtime)
0393         date_time = mtime[0:6]
0394         # Create ZipInfo instance to store file information
0395         if arcname is None:
0396             zinfo = ZipInfo(filename, date_time)
0397         else:
0398             zinfo = ZipInfo(arcname, date_time)
0399         zinfo.external_attr = (st[0] & 0xFFFF) << 16L      # Unix attributes
0400         if compress_type is None:
0401             zinfo.compress_type = self.compression
0402         else:
0403             zinfo.compress_type = compress_type
0404         self._writecheck(zinfo)
0405         fp = open(filename, "rb")
0406         zinfo.flag_bits = 0x00
0407         zinfo.header_offset = self.fp.tell()    # Start of header bytes
0408         # Must overwrite CRC and sizes with correct data later
0409         zinfo.CRC = CRC = 0
0410         zinfo.compress_size = compress_size = 0
0411         zinfo.file_size = file_size = 0
0412         self.fp.write(zinfo.FileHeader())
0413         zinfo.file_offset = self.fp.tell()      # Start of file bytes
0414         if zinfo.compress_type == ZIP_DEFLATED:
0415             cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
0416                  zlib.DEFLATED, -15)
0417         else:
0418             cmpr = None
0419         while 1:
0420             buf = fp.read(1024 * 8)
0421             if not buf:
0422                 break
0423             file_size = file_size + len(buf)
0424             CRC = binascii.crc32(buf, CRC)
0425             if cmpr:
0426                 buf = cmpr.compress(buf)
0427                 compress_size = compress_size + len(buf)
0428             self.fp.write(buf)
0429         fp.close()
0430         if cmpr:
0431             buf = cmpr.flush()
0432             compress_size = compress_size + len(buf)
0433             self.fp.write(buf)
0434             zinfo.compress_size = compress_size
0435         else:
0436             zinfo.compress_size = file_size
0437         zinfo.CRC = CRC
0438         zinfo.file_size = file_size
0439         # Seek backwards and write CRC and file sizes
0440         position = self.fp.tell()       # Preserve current position in file
0441         self.fp.seek(zinfo.header_offset + 14, 0)
0442         self.fp.write(struct.pack("<lLL", zinfo.CRC, zinfo.compress_size,
0443               zinfo.file_size))
0444         self.fp.seek(position, 0)
0445         self.filelist.append(zinfo)
0446         self.NameToInfo[zinfo.filename] = zinfo
0447 
0448     def writestr(self, zinfo_or_arcname, bytes):
0449         """Write a file into the archive.  The contents is the string
0450         'bytes'.  'zinfo_or_arcname' is either a ZipInfo instance or
0451         the name of the file in the archive."""
0452         if not isinstance(zinfo_or_arcname, ZipInfo):
0453             zinfo = ZipInfo(filename=zinfo_or_arcname,
0454                             date_time=time.localtime(time.time()))
0455             zinfo.compress_type = self.compression
0456         else:
0457             zinfo = zinfo_or_arcname
0458         self._writecheck(zinfo)
0459         zinfo.file_size = len(bytes)            # Uncompressed size
0460         zinfo.CRC = binascii.crc32(bytes)       # CRC-32 checksum
0461         if zinfo.compress_type == ZIP_DEFLATED:
0462             co = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
0463                  zlib.DEFLATED, -15)
0464             bytes = co.compress(bytes) + co.flush()
0465             zinfo.compress_size = len(bytes)    # Compressed size
0466         else:
0467             zinfo.compress_size = zinfo.file_size
0468         zinfo.header_offset = self.fp.tell()    # Start of header bytes
0469         self.fp.write(zinfo.FileHeader())
0470         zinfo.file_offset = self.fp.tell()      # Start of file bytes
0471         self.fp.write(bytes)
0472         if zinfo.flag_bits & 0x08:
0473             # Write CRC and file sizes after the file data
0474             self.fp.write(struct.pack("<lLL", zinfo.CRC, zinfo.compress_size,
0475                   zinfo.file_size))
0476         self.filelist.append(zinfo)
0477         self.NameToInfo[zinfo.filename] = zinfo
0478 
0479     def __del__(self):
0480         """Call the "close()" method in case the user forgot."""
0481         self.close()
0482 
0483     def close(self):
0484         """Close the file, and for mode "w" and "a" write the ending
0485         records."""
0486         if self.fp is None:
0487             return
0488         if self.mode in ("w", "a"):             # write ending records
0489             count = 0
0490             pos1 = self.fp.tell()
0491             for zinfo in self.filelist:         # write central directory
0492                 count = count + 1
0493                 dt = zinfo.date_time
0494                 dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
0495                 dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
0496                 centdir = struct.pack(structCentralDir,
0497                   stringCentralDir, zinfo.create_version,
0498                   zinfo.create_system, zinfo.extract_version, zinfo.reserved,
0499                   zinfo.flag_bits, zinfo.compress_type, dostime, dosdate,
0500                   zinfo.CRC, zinfo.compress_size, zinfo.file_size,
0501                   len(zinfo.filename), len(zinfo.extra), len(zinfo.comment),
0502                   0, zinfo.internal_attr, zinfo.external_attr,
0503                   zinfo.header_offset)
0504                 self.fp.write(centdir)
0505                 self.fp.write(zinfo.filename)
0506                 self.fp.write(zinfo.extra)
0507                 self.fp.write(zinfo.comment)
0508             pos2 = self.fp.tell()
0509             # Write end-of-zip-archive record
0510             endrec = struct.pack(structEndArchive, stringEndArchive,
0511                      0, 0, count, count, pos2 - pos1, pos1, 0)
0512             self.fp.write(endrec)
0513             self.fp.flush()
0514         if not self._filePassed:
0515             self.fp.close()
0516         self.fp = None
0517 
0518 
0519 class PyZipFile(ZipFile):
0520     """Class to create ZIP archives with Python library files and packages."""
0521 
0522     def writepy(self, pathname, basename = ""):
0523         """Add all files from "pathname" to the ZIP archive.
0524 
0525         If pathname is a package directory, search the directory and
0526         all package subdirectories recursively for all *.py and enter
0527         the modules into the archive.  If pathname is a plain
0528         directory, listdir *.py and enter all modules.  Else, pathname
0529         must be a Python *.py file and the module will be put into the
0530         archive.  Added modules are always module.pyo or module.pyc.
0531         This method will compile the module.py into module.pyc if
0532         necessary.
0533         """
0534         dir, name = os.path.split(pathname)
0535         if os.path.isdir(pathname):
0536             initname = os.path.join(pathname, "__init__.py")
0537             if os.path.isfile(initname):
0538                 # This is a package directory, add it
0539                 if basename:
0540                     basename = "%s/%s" % (basename, name)
0541                 else:
0542                     basename = name
0543                 if self.debug:
0544                     print "Adding package in", pathname, "as", basename
0545                 fname, arcname = self._get_codename(initname[0:-3], basename)
0546                 if self.debug:
0547                     print "Adding", arcname
0548                 self.write(fname, arcname)
0549                 dirlist = os.listdir(pathname)
0550                 dirlist.remove("__init__.py")
0551                 # Add all *.py files and package subdirectories
0552                 for filename in dirlist:
0553                     path = os.path.join(pathname, filename)
0554                     root, ext = os.path.splitext(filename)
0555                     if os.path.isdir(path):
0556                         if os.path.isfile(os.path.join(path, "__init__.py")):
0557                             # This is a package directory, add it
0558                             self.writepy(path, basename)  # Recursive call
0559                     elif ext == ".py":
0560                         fname, arcname = self._get_codename(path[0:-3],
0561                                          basename)
0562                         if self.debug:
0563                             print "Adding", arcname
0564                         self.write(fname, arcname)
0565             else:
0566                 # This is NOT a package directory, add its files at top level
0567                 if self.debug:
0568                     print "Adding files from directory", pathname
0569                 for filename in os.listdir(pathname):
0570                     path = os.path.join(pathname, filename)
0571                     root, ext = os.path.splitext(filename)
0572                     if ext == ".py":
0573                         fname, arcname = self._get_codename(path[0:-3],
0574                                          basename)
0575                         if self.debug:
0576                             print "Adding", arcname
0577                         self.write(fname, arcname)
0578         else:
0579             if pathname[-3:] != ".py":
0580                 raise RuntimeError, \
0581                       'Files added with writepy() must end with ".py"'
0582             fname, arcname = self._get_codename(pathname[0:-3], basename)
0583             if self.debug:
0584                 print "Adding file", arcname
0585             self.write(fname, arcname)
0586 
0587     def _get_codename(self, pathname, basename):
0588         """Return (filename, archivename) for the path.
0589 
0590         Given a module name path, return the correct file path and
0591         archive name, compiling if necessary.  For example, given
0592         /python/lib/string, return (/python/lib/string.pyc, string).
0593         """
0594         file_py  = pathname + ".py"
0595         file_pyc = pathname + ".pyc"
0596         file_pyo = pathname + ".pyo"
0597         if os.path.isfile(file_pyo) and \
0598                             os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime:
0599             fname = file_pyo    # Use .pyo file
0600         elif not os.path.isfile(file_pyc) or \
0601              os.stat(file_pyc).st_mtime < os.stat(file_py).st_mtime:
0602             import py_compile
0603             if self.debug:
0604                 print "Compiling", file_py
0605             try:
0606                 py_compile.compile(file_py, file_pyc, None, True)
0607             except py_compile.PyCompileError,err:
0608                 print err.msg
0609             fname = file_pyc
0610         else:
0611             fname = file_pyc
0612         archivename = os.path.split(fname)[1]
0613         if basename:
0614             archivename = "%s/%s" % (basename, archivename)
0615         return (fname, archivename)
0616 

Generated by PyXR 0.9.4
SourceForge.net Logo