diff options
-rw-r--r-- | Lib/Queue.py | 2 | ||||
-rw-r--r-- | Lib/StringIO.py | 54 | ||||
-rw-r--r-- | Lib/UserDict.py | 2 | ||||
-rw-r--r-- | Lib/UserList.py | 2 | ||||
-rw-r--r-- | Lib/aifc.py | 1835 | ||||
-rw-r--r-- | Lib/audiodev.py | 2 | ||||
-rwxr-xr-x | Lib/base64.py | 112 | ||||
-rw-r--r-- | Lib/bdb.py | 1052 | ||||
-rw-r--r-- | Lib/binhex.py | 941 | ||||
-rw-r--r-- | Lib/bisect.py | 36 | ||||
-rw-r--r-- | Lib/calendar.py | 234 | ||||
-rw-r--r-- | Lib/cmd.py | 360 | ||||
-rw-r--r-- | Lib/cmp.py | 108 | ||||
-rw-r--r-- | Lib/cmpcache.py | 100 | ||||
-rw-r--r-- | Lib/copy_reg.py | 2 | ||||
-rw-r--r-- | Lib/dircache.py | 54 | ||||
-rw-r--r-- | Lib/dircmp.py | 368 | ||||
-rw-r--r-- | Lib/fpformat.py | 18 |
18 files changed, 2640 insertions, 2642 deletions
diff --git a/Lib/Queue.py b/Lib/Queue.py index e0e9693..cb04006 100644 --- a/Lib/Queue.py +++ b/Lib/Queue.py @@ -1,4 +1,4 @@ -# A multi-producer, multi-consumer queue. +"""A multi-producer, multi-consumer queue.""" # define this exception to be compatible with Python 1.5's class # exceptions, but also when -X option is used. diff --git a/Lib/StringIO.py b/Lib/StringIO.py index fc195b9..04ffec9 100644 --- a/Lib/StringIO.py +++ b/Lib/StringIO.py @@ -1,30 +1,30 @@ -# class StringIO implements file-like objects that read/write a -# string buffer (a.k.a. "memory files"). -# -# This implements (nearly) all stdio methods. -# -# f = StringIO() # ready for writing -# f = StringIO(buf) # ready for reading -# f.close() # explicitly release resources held -# flag = f.isatty() # always false -# pos = f.tell() # get current position -# f.seek(pos) # set current position -# f.seek(pos, mode) # mode 0: absolute; 1: relative; 2: relative to EOF -# buf = f.read() # read until EOF -# buf = f.read(n) # read up to n bytes -# buf = f.readline() # read until end of line ('\n') or EOF -# list = f.readlines()# list of f.readline() results until EOF -# f.write(buf) # write at current position -# f.writelines(list) # for line in list: f.write(line) -# f.getvalue() # return whole file's contents as a string -# -# Notes: -# - Using a real file is often faster (but less convenient). -# - fileno() is left unimplemented so that code which uses it triggers -# an exception early. -# - Seeking far beyond EOF and then writing will insert real null -# bytes that occupy space in the buffer. -# - There's a simple test set (see end of this file). +"""File-like objects that read from or write to a string buffer. + +This implements (nearly) all stdio methods. + +f = StringIO() # ready for writing +f = StringIO(buf) # ready for reading +f.close() # explicitly release resources held +flag = f.isatty() # always false +pos = f.tell() # get current position +f.seek(pos) # set current position +f.seek(pos, mode) # mode 0: absolute; 1: relative; 2: relative to EOF +buf = f.read() # read until EOF +buf = f.read(n) # read up to n bytes +buf = f.readline() # read until end of line ('\n') or EOF +list = f.readlines()# list of f.readline() results until EOF +f.write(buf) # write at current position +f.writelines(list) # for line in list: f.write(line) +f.getvalue() # return whole file's contents as a string + +Notes: +- Using a real file is often faster (but less convenient). +- fileno() is left unimplemented so that code which uses it triggers + an exception early. +- Seeking far beyond EOF and then writing will insert real null + bytes that occupy space in the buffer. +- There's a simple test set (see end of this file). +""" import string diff --git a/Lib/UserDict.py b/Lib/UserDict.py index 50fee89..3c48415 100644 --- a/Lib/UserDict.py +++ b/Lib/UserDict.py @@ -1,4 +1,4 @@ -# A more or less complete user-defined wrapper around dictionary objects +"""A more or less complete user-defined wrapper around dictionary objects.""" class UserDict: def __init__(self, dict=None): diff --git a/Lib/UserList.py b/Lib/UserList.py index a60d8ce..1680327 100644 --- a/Lib/UserList.py +++ b/Lib/UserList.py @@ -1,4 +1,4 @@ -# A more or less complete user-defined wrapper around list objects +"""A more or less complete user-defined wrapper around list objects.""" class UserList: def __init__(self, list=None): diff --git a/Lib/aifc.py b/Lib/aifc.py index 6c19dea..f7288d5 100644 --- a/Lib/aifc.py +++ b/Lib/aifc.py @@ -1,957 +1,958 @@ -# Stuff to parse AIFF-C and AIFF files. -# -# Unless explicitly stated otherwise, the description below is true -# both for AIFF-C files and AIFF files. -# -# An AIFF-C file has the following structure. -# -# +-----------------+ -# | FORM | -# +-----------------+ -# | <size> | -# +----+------------+ -# | | AIFC | -# | +------------+ -# | | <chunks> | -# | | . | -# | | . | -# | | . | -# +----+------------+ -# -# An AIFF file has the string "AIFF" instead of "AIFC". -# -# A chunk consists of an identifier (4 bytes) followed by a size (4 bytes, -# big endian order), followed by the data. The size field does not include -# the size of the 8 byte header. -# -# The following chunk types are recognized. -# -# FVER -# <version number of AIFF-C defining document> (AIFF-C only). -# MARK -# <# of markers> (2 bytes) -# list of markers: -# <marker ID> (2 bytes, must be > 0) -# <position> (4 bytes) -# <marker name> ("pstring") -# COMM -# <# of channels> (2 bytes) -# <# of sound frames> (4 bytes) -# <size of the samples> (2 bytes) -# <sampling frequency> (10 bytes, IEEE 80-bit extended -# floating point) -# in AIFF-C files only: -# <compression type> (4 bytes) -# <human-readable version of compression type> ("pstring") -# SSND -# <offset> (4 bytes, not used by this program) -# <blocksize> (4 bytes, not used by this program) -# <sound data> -# -# A pstring consists of 1 byte length, a string of characters, and 0 or 1 -# byte pad to make the total length even. -# -# Usage. -# -# Reading AIFF files: -# f = aifc.open(file, 'r') -# where file is either the name of a file or an open file pointer. -# The open file pointer must have methods read(), seek(), and close(). -# In some types of audio files, if the setpos() method is not used, -# the seek() method is not necessary. -# -# This returns an instance of a class with the following public methods: -# getnchannels() -- returns number of audio channels (1 for -# mono, 2 for stereo) -# getsampwidth() -- returns sample width in bytes -# getframerate() -- returns sampling frequency -# getnframes() -- returns number of audio frames -# getcomptype() -- returns compression type ('NONE' for AIFF files) -# getcompname() -- returns human-readable version of -# compression type ('not compressed' for AIFF files) -# getparams() -- returns a tuple consisting of all of the -# above in the above order -# getmarkers() -- get the list of marks in the audio file or None -# if there are no marks -# getmark(id) -- get mark with the specified id (raises an error -# if the mark does not exist) -# readframes(n) -- returns at most n frames of audio -# rewind() -- rewind to the beginning of the audio stream -# setpos(pos) -- seek to the specified position -# tell() -- return the current position -# close() -- close the instance (make it unusable) -# The position returned by tell(), the position given to setpos() and -# the position of marks are all compatible and have nothing to do with -# the actual postion in the file. -# The close() method is called automatically when the class instance -# is destroyed. -# -# Writing AIFF files: -# f = aifc.open(file, 'w') -# where file is either the name of a file or an open file pointer. -# The open file pointer must have methods write(), tell(), seek(), and -# close(). -# -# This returns an instance of a class with the following public methods: -# aiff() -- create an AIFF file (AIFF-C default) -# aifc() -- create an AIFF-C file -# setnchannels(n) -- set the number of channels -# setsampwidth(n) -- set the sample width -# setframerate(n) -- set the frame rate -# setnframes(n) -- set the number of frames -# setcomptype(type, name) -# -- set the compression type and the -# human-readable compression type -# setparams(tuple) -# -- set all parameters at once -# setmark(id, pos, name) -# -- add specified mark to the list of marks -# tell() -- return current position in output file (useful -# in combination with setmark()) -# writeframesraw(data) -# -- write audio frames without pathing up the -# file header -# writeframes(data) -# -- write audio frames and patch up the file header -# close() -- patch up the file header and close the -# output file -# You should set the parameters before the first writeframesraw or -# writeframes. The total number of frames does not need to be set, -# but when it is set to the correct value, the header does not have to -# be patched up. -# It is best to first set all parameters, perhaps possibly the -# compression type, and then write audio frames using writeframesraw. -# When all frames have been written, either call writeframes('') or -# close() to patch up the sizes in the header. -# Marks can be added anytime. If there are any marks, ypu must call -# close() after all frames have been written. -# The close() method is called automatically when the class instance -# is destroyed. -# -# When a file is opened with the extension '.aiff', an AIFF file is -# written, otherwise an AIFF-C file is written. This default can be -# changed by calling aiff() or aifc() before the first writeframes or -# writeframesraw. +"""Stuff to parse AIFF-C and AIFF files. + +Unless explicitly stated otherwise, the description below is true +both for AIFF-C files and AIFF files. + +An AIFF-C file has the following structure. + + +-----------------+ + | FORM | + +-----------------+ + | <size> | + +----+------------+ + | | AIFC | + | +------------+ + | | <chunks> | + | | . | + | | . | + | | . | + +----+------------+ + +An AIFF file has the string "AIFF" instead of "AIFC". + +A chunk consists of an identifier (4 bytes) followed by a size (4 bytes, +big endian order), followed by the data. The size field does not include +the size of the 8 byte header. + +The following chunk types are recognized. + + FVER + <version number of AIFF-C defining document> (AIFF-C only). + MARK + <# of markers> (2 bytes) + list of markers: + <marker ID> (2 bytes, must be > 0) + <position> (4 bytes) + <marker name> ("pstring") + COMM + <# of channels> (2 bytes) + <# of sound frames> (4 bytes) + <size of the samples> (2 bytes) + <sampling frequency> (10 bytes, IEEE 80-bit extended + floating point) + in AIFF-C files only: + <compression type> (4 bytes) + <human-readable version of compression type> ("pstring") + SSND + <offset> (4 bytes, not used by this program) + <blocksize> (4 bytes, not used by this program) + <sound data> + +A pstring consists of 1 byte length, a string of characters, and 0 or 1 +byte pad to make the total length even. + +Usage. + +Reading AIFF files: + f = aifc.open(file, 'r') +where file is either the name of a file or an open file pointer. +The open file pointer must have methods read(), seek(), and close(). +In some types of audio files, if the setpos() method is not used, +the seek() method is not necessary. + +This returns an instance of a class with the following public methods: + getnchannels() -- returns number of audio channels (1 for + mono, 2 for stereo) + getsampwidth() -- returns sample width in bytes + getframerate() -- returns sampling frequency + getnframes() -- returns number of audio frames + getcomptype() -- returns compression type ('NONE' for AIFF files) + getcompname() -- returns human-readable version of + compression type ('not compressed' for AIFF files) + getparams() -- returns a tuple consisting of all of the + above in the above order + getmarkers() -- get the list of marks in the audio file or None + if there are no marks + getmark(id) -- get mark with the specified id (raises an error + if the mark does not exist) + readframes(n) -- returns at most n frames of audio + rewind() -- rewind to the beginning of the audio stream + setpos(pos) -- seek to the specified position + tell() -- return the current position + close() -- close the instance (make it unusable) +The position returned by tell(), the position given to setpos() and +the position of marks are all compatible and have nothing to do with +the actual postion in the file. +The close() method is called automatically when the class instance +is destroyed. + +Writing AIFF files: + f = aifc.open(file, 'w') +where file is either the name of a file or an open file pointer. +The open file pointer must have methods write(), tell(), seek(), and +close(). + +This returns an instance of a class with the following public methods: + aiff() -- create an AIFF file (AIFF-C default) + aifc() -- create an AIFF-C file + setnchannels(n) -- set the number of channels + setsampwidth(n) -- set the sample width + setframerate(n) -- set the frame rate + setnframes(n) -- set the number of frames + setcomptype(type, name) + -- set the compression type and the + human-readable compression type + setparams(tuple) + -- set all parameters at once + setmark(id, pos, name) + -- add specified mark to the list of marks + tell() -- return current position in output file (useful + in combination with setmark()) + writeframesraw(data) + -- write audio frames without pathing up the + file header + writeframes(data) + -- write audio frames and patch up the file header + close() -- patch up the file header and close the + output file +You should set the parameters before the first writeframesraw or +writeframes. The total number of frames does not need to be set, +but when it is set to the correct value, the header does not have to +be patched up. +It is best to first set all parameters, perhaps possibly the +compression type, and then write audio frames using writeframesraw. +When all frames have been written, either call writeframes('') or +close() to patch up the sizes in the header. +Marks can be added anytime. If there are any marks, ypu must call +close() after all frames have been written. +The close() method is called automatically when the class instance +is destroyed. + +When a file is opened with the extension '.aiff', an AIFF file is +written, otherwise an AIFF-C file is written. This default can be +changed by calling aiff() or aifc() before the first writeframes or +writeframesraw. +""" import struct import __builtin__ Error = 'aifc.Error' -_AIFC_version = 0xA2805140 # Version 1 of AIFF-C +_AIFC_version = 0xA2805140 # Version 1 of AIFF-C _skiplist = 'COMT', 'INST', 'MIDI', 'AESD', \ - 'APPL', 'NAME', 'AUTH', '(c) ', 'ANNO' + 'APPL', 'NAME', 'AUTH', '(c) ', 'ANNO' def _read_long(file): - try: - return struct.unpack('>l', file.read(4))[0] - except struct.error: - raise EOFError + try: + return struct.unpack('>l', file.read(4))[0] + except struct.error: + raise EOFError def _read_ulong(file): - try: - return struct.unpack('>L', file.read(4))[0] - except struct.error: - raise EOFError + try: + return struct.unpack('>L', file.read(4))[0] + except struct.error: + raise EOFError def _read_short(file): - try: - return struct.unpack('>h', file.read(2))[0] - except struct.error: - raise EOFError + try: + return struct.unpack('>h', file.read(2))[0] + except struct.error: + raise EOFError def _read_string(file): - length = ord(file.read(1)) - if length == 0: - data = '' - else: - data = file.read(length) - if length & 1 == 0: - dummy = file.read(1) - return data + length = ord(file.read(1)) + if length == 0: + data = '' + else: + data = file.read(length) + if length & 1 == 0: + dummy = file.read(1) + return data _HUGE_VAL = 1.79769313486231e+308 # See <limits.h> def _read_float(f): # 10 bytes - import math - expon = _read_short(f) # 2 bytes - sign = 1 - if expon < 0: - sign = -1 - expon = expon + 0x8000 - himant = _read_ulong(f) # 4 bytes - lomant = _read_ulong(f) # 4 bytes - if expon == himant == lomant == 0: - f = 0.0 - elif expon == 0x7FFF: - f = _HUGE_VAL - else: - expon = expon - 16383 - f = (himant * 0x100000000L + lomant) * pow(2.0, expon - 63) - return sign * f + import math + expon = _read_short(f) # 2 bytes + sign = 1 + if expon < 0: + sign = -1 + expon = expon + 0x8000 + himant = _read_ulong(f) # 4 bytes + lomant = _read_ulong(f) # 4 bytes + if expon == himant == lomant == 0: + f = 0.0 + elif expon == 0x7FFF: + f = _HUGE_VAL + else: + expon = expon - 16383 + f = (himant * 0x100000000L + lomant) * pow(2.0, expon - 63) + return sign * f def _write_short(f, x): - f.write(struct.pack('>h', x)) + f.write(struct.pack('>h', x)) def _write_long(f, x): - f.write(struct.pack('>L', x)) + f.write(struct.pack('>L', x)) def _write_string(f, s): - f.write(chr(len(s))) - f.write(s) - if len(s) & 1 == 0: - f.write(chr(0)) + f.write(chr(len(s))) + f.write(s) + if len(s) & 1 == 0: + f.write(chr(0)) def _write_float(f, x): - import math - if x < 0: - sign = 0x8000 - x = x * -1 - else: - sign = 0 - if x == 0: - expon = 0 - himant = 0 - lomant = 0 - else: - fmant, expon = math.frexp(x) - if expon > 16384 or fmant >= 1: # Infinity or NaN - expon = sign|0x7FFF - himant = 0 - lomant = 0 - else: # Finite - expon = expon + 16382 - if expon < 0: # denormalized - fmant = math.ldexp(fmant, expon) - expon = 0 - expon = expon | sign - fmant = math.ldexp(fmant, 32) - fsmant = math.floor(fmant) - himant = long(fsmant) - fmant = math.ldexp(fmant - fsmant, 32) - fsmant = math.floor(fmant) - lomant = long(fsmant) - _write_short(f, expon) - _write_long(f, himant) - _write_long(f, lomant) + import math + if x < 0: + sign = 0x8000 + x = x * -1 + else: + sign = 0 + if x == 0: + expon = 0 + himant = 0 + lomant = 0 + else: + fmant, expon = math.frexp(x) + if expon > 16384 or fmant >= 1: # Infinity or NaN + expon = sign|0x7FFF + himant = 0 + lomant = 0 + else: # Finite + expon = expon + 16382 + if expon < 0: # denormalized + fmant = math.ldexp(fmant, expon) + expon = 0 + expon = expon | sign + fmant = math.ldexp(fmant, 32) + fsmant = math.floor(fmant) + himant = long(fsmant) + fmant = math.ldexp(fmant - fsmant, 32) + fsmant = math.floor(fmant) + lomant = long(fsmant) + _write_short(f, expon) + _write_long(f, himant) + _write_long(f, lomant) from chunk import Chunk class Aifc_read: - # Variables used in this class: - # - # These variables are available to the user though appropriate - # methods of this class: - # _file -- the open file with methods read(), close(), and seek() - # set through the __init__() method - # _nchannels -- the number of audio channels - # available through the getnchannels() method - # _nframes -- the number of audio frames - # available through the getnframes() method - # _sampwidth -- the number of bytes per audio sample - # available through the getsampwidth() method - # _framerate -- the sampling frequency - # available through the getframerate() method - # _comptype -- the AIFF-C compression type ('NONE' if AIFF) - # available through the getcomptype() method - # _compname -- the human-readable AIFF-C compression type - # available through the getcomptype() method - # _markers -- the marks in the audio file - # available through the getmarkers() and getmark() - # methods - # _soundpos -- the position in the audio stream - # available through the tell() method, set through the - # setpos() method - # - # These variables are used internally only: - # _version -- the AIFF-C version number - # _decomp -- the decompressor from builtin module cl - # _comm_chunk_read -- 1 iff the COMM chunk has been read - # _aifc -- 1 iff reading an AIFF-C file - # _ssnd_seek_needed -- 1 iff positioned correctly in audio - # file for readframes() - # _ssnd_chunk -- instantiation of a chunk class for the SSND chunk - # _framesize -- size of one frame in the file - - def initfp(self, file): - self._version = 0 - self._decomp = None - self._convert = None - self._markers = [] - self._soundpos = 0 - self._file = Chunk(file) - if self._file.getname() != 'FORM': - raise Error, 'file does not start with FORM id' - formdata = self._file.read(4) - if formdata == 'AIFF': - self._aifc = 0 - elif formdata == 'AIFC': - self._aifc = 1 - else: - raise Error, 'not an AIFF or AIFF-C file' - self._comm_chunk_read = 0 - while 1: - self._ssnd_seek_needed = 1 - try: - chunk = Chunk(self._file) - except EOFError: - break - chunkname = chunk.getname() - if chunkname == 'COMM': - self._read_comm_chunk(chunk) - self._comm_chunk_read = 1 - elif chunkname == 'SSND': - self._ssnd_chunk = chunk - dummy = chunk.read(8) - self._ssnd_seek_needed = 0 - elif chunkname == 'FVER': - self._version = _read_long(chunk) - elif chunkname == 'MARK': - self._readmark(chunk) - elif chunkname in _skiplist: - pass - else: - raise Error, 'unrecognized chunk type '+chunk.chunkname - chunk.skip() - if not self._comm_chunk_read or not self._ssnd_chunk: - raise Error, 'COMM chunk and/or SSND chunk missing' - if self._aifc and self._decomp: - import cl - params = [cl.ORIGINAL_FORMAT, 0, - cl.BITS_PER_COMPONENT, self._sampwidth * 8, - cl.FRAME_RATE, self._framerate] - if self._nchannels == 1: - params[1] = cl.MONO - elif self._nchannels == 2: - params[1] = cl.STEREO_INTERLEAVED - else: - raise Error, 'cannot compress more than 2 channels' - self._decomp.SetParams(params) - - def __init__(self, f): - if type(f) == type(''): - f = __builtin__.open(f, 'rb') - # else, assume it is an open file object already - self.initfp(f) - - # - # User visible methods. - # - def getfp(self): - return self._file - - def rewind(self): - self._ssnd_seek_needed = 1 - self._soundpos = 0 - - def close(self): - if self._decomp: - self._decomp.CloseDecompressor() - self._decomp = None - self._file = None - - def tell(self): - return self._soundpos - - def getnchannels(self): - return self._nchannels - - def getnframes(self): - return self._nframes - - def getsampwidth(self): - return self._sampwidth - - def getframerate(self): - return self._framerate - - def getcomptype(self): - return self._comptype - - def getcompname(self): - return self._compname - -## def getversion(self): -## return self._version - - def getparams(self): - return self.getnchannels(), self.getsampwidth(), \ - self.getframerate(), self.getnframes(), \ - self.getcomptype(), self.getcompname() - - def getmarkers(self): - if len(self._markers) == 0: - return None - return self._markers - - def getmark(self, id): - for marker in self._markers: - if id == marker[0]: - return marker - raise Error, 'marker ' + `id` + ' does not exist' - - def setpos(self, pos): - if pos < 0 or pos > self._nframes: - raise Error, 'position not in range' - self._soundpos = pos - self._ssnd_seek_needed = 1 - - def readframes(self, nframes): - if self._ssnd_seek_needed: - self._ssnd_chunk.seek(0) - dummy = self._ssnd_chunk.read(8) - pos = self._soundpos * self._framesize - if pos: - self._ssnd_chunk.setpos(pos + 8) - self._ssnd_seek_needed = 0 - if nframes == 0: - return '' - data = self._ssnd_chunk.read(nframes * self._framesize) - if self._convert and data: - data = self._convert(data) - self._soundpos = self._soundpos + len(data) / (self._nchannels * self._sampwidth) - return data - - # - # Internal methods. - # - - def _decomp_data(self, data): - import cl - dummy = self._decomp.SetParam(cl.FRAME_BUFFER_SIZE, - len(data) * 2) - return self._decomp.Decompress(len(data) / self._nchannels, - data) - - def _ulaw2lin(self, data): - import audioop - return audioop.ulaw2lin(data, 2) - - def _adpcm2lin(self, data): - import audioop - if not hasattr(self, '_adpcmstate'): - # first time - self._adpcmstate = None - data, self._adpcmstate = audioop.adpcm2lin(data, 2, - self._adpcmstate) - return data - - def _read_comm_chunk(self, chunk): - self._nchannels = _read_short(chunk) - self._nframes = _read_long(chunk) - self._sampwidth = (_read_short(chunk) + 7) / 8 - self._framerate = int(_read_float(chunk)) - self._framesize = self._nchannels * self._sampwidth - if self._aifc: - #DEBUG: SGI's soundeditor produces a bad size :-( - kludge = 0 - if chunk.chunksize == 18: - kludge = 1 - print 'Warning: bad COMM chunk size' - chunk.chunksize = 23 - #DEBUG end - self._comptype = chunk.read(4) - #DEBUG start - if kludge: - length = ord(chunk.file.read(1)) - if length & 1 == 0: - length = length + 1 - chunk.chunksize = chunk.chunksize + length - chunk.file.seek(-1, 1) - #DEBUG end - self._compname = _read_string(chunk) - if self._comptype != 'NONE': - if self._comptype == 'G722': - try: - import audioop - except ImportError: - pass - else: - self._convert = self._adpcm2lin - self._framesize = self._framesize / 4 - return - # for ULAW and ALAW try Compression Library - try: - import cl - except ImportError: - if self._comptype == 'ULAW': - try: - import audioop - self._convert = self._ulaw2lin - self._framesize = self._framesize / 2 - return - except ImportError: - pass - raise Error, 'cannot read compressed AIFF-C files' - if self._comptype == 'ULAW': - scheme = cl.G711_ULAW - self._framesize = self._framesize / 2 - elif self._comptype == 'ALAW': - scheme = cl.G711_ALAW - self._framesize = self._framesize / 2 - else: - raise Error, 'unsupported compression type' - self._decomp = cl.OpenDecompressor(scheme) - self._convert = self._decomp_data - else: - self._comptype = 'NONE' - self._compname = 'not compressed' - - def _readmark(self, chunk): - nmarkers = _read_short(chunk) - # Some files appear to contain invalid counts. - # Cope with this by testing for EOF. - try: - for i in range(nmarkers): - id = _read_short(chunk) - pos = _read_long(chunk) - name = _read_string(chunk) - if pos or name: - # some files appear to have - # dummy markers consisting of - # a position 0 and name '' - self._markers.append((id, pos, name)) - except EOFError: - print 'Warning: MARK chunk contains only', - print len(self._markers), - if len(self._markers) == 1: print 'marker', - else: print 'markers', - print 'instead of', nmarkers + # Variables used in this class: + # + # These variables are available to the user though appropriate + # methods of this class: + # _file -- the open file with methods read(), close(), and seek() + # set through the __init__() method + # _nchannels -- the number of audio channels + # available through the getnchannels() method + # _nframes -- the number of audio frames + # available through the getnframes() method + # _sampwidth -- the number of bytes per audio sample + # available through the getsampwidth() method + # _framerate -- the sampling frequency + # available through the getframerate() method + # _comptype -- the AIFF-C compression type ('NONE' if AIFF) + # available through the getcomptype() method + # _compname -- the human-readable AIFF-C compression type + # available through the getcomptype() method + # _markers -- the marks in the audio file + # available through the getmarkers() and getmark() + # methods + # _soundpos -- the position in the audio stream + # available through the tell() method, set through the + # setpos() method + # + # These variables are used internally only: + # _version -- the AIFF-C version number + # _decomp -- the decompressor from builtin module cl + # _comm_chunk_read -- 1 iff the COMM chunk has been read + # _aifc -- 1 iff reading an AIFF-C file + # _ssnd_seek_needed -- 1 iff positioned correctly in audio + # file for readframes() + # _ssnd_chunk -- instantiation of a chunk class for the SSND chunk + # _framesize -- size of one frame in the file + + def initfp(self, file): + self._version = 0 + self._decomp = None + self._convert = None + self._markers = [] + self._soundpos = 0 + self._file = Chunk(file) + if self._file.getname() != 'FORM': + raise Error, 'file does not start with FORM id' + formdata = self._file.read(4) + if formdata == 'AIFF': + self._aifc = 0 + elif formdata == 'AIFC': + self._aifc = 1 + else: + raise Error, 'not an AIFF or AIFF-C file' + self._comm_chunk_read = 0 + while 1: + self._ssnd_seek_needed = 1 + try: + chunk = Chunk(self._file) + except EOFError: + break + chunkname = chunk.getname() + if chunkname == 'COMM': + self._read_comm_chunk(chunk) + self._comm_chunk_read = 1 + elif chunkname == 'SSND': + self._ssnd_chunk = chunk + dummy = chunk.read(8) + self._ssnd_seek_needed = 0 + elif chunkname == 'FVER': + self._version = _read_long(chunk) + elif chunkname == 'MARK': + self._readmark(chunk) + elif chunkname in _skiplist: + pass + else: + raise Error, 'unrecognized chunk type '+chunk.chunkname + chunk.skip() + if not self._comm_chunk_read or not self._ssnd_chunk: + raise Error, 'COMM chunk and/or SSND chunk missing' + if self._aifc and self._decomp: + import cl + params = [cl.ORIGINAL_FORMAT, 0, + cl.BITS_PER_COMPONENT, self._sampwidth * 8, + cl.FRAME_RATE, self._framerate] + if self._nchannels == 1: + params[1] = cl.MONO + elif self._nchannels == 2: + params[1] = cl.STEREO_INTERLEAVED + else: + raise Error, 'cannot compress more than 2 channels' + self._decomp.SetParams(params) + + def __init__(self, f): + if type(f) == type(''): + f = __builtin__.open(f, 'rb') + # else, assume it is an open file object already + self.initfp(f) + + # + # User visible methods. + # + def getfp(self): + return self._file + + def rewind(self): + self._ssnd_seek_needed = 1 + self._soundpos = 0 + + def close(self): + if self._decomp: + self._decomp.CloseDecompressor() + self._decomp = None + self._file = None + + def tell(self): + return self._soundpos + + def getnchannels(self): + return self._nchannels + + def getnframes(self): + return self._nframes + + def getsampwidth(self): + return self._sampwidth + + def getframerate(self): + return self._framerate + + def getcomptype(self): + return self._comptype + + def getcompname(self): + return self._compname + +## def getversion(self): +## return self._version + + def getparams(self): + return self.getnchannels(), self.getsampwidth(), \ + self.getframerate(), self.getnframes(), \ + self.getcomptype(), self.getcompname() + + def getmarkers(self): + if len(self._markers) == 0: + return None + return self._markers + + def getmark(self, id): + for marker in self._markers: + if id == marker[0]: + return marker + raise Error, 'marker ' + `id` + ' does not exist' + + def setpos(self, pos): + if pos < 0 or pos > self._nframes: + raise Error, 'position not in range' + self._soundpos = pos + self._ssnd_seek_needed = 1 + + def readframes(self, nframes): + if self._ssnd_seek_needed: + self._ssnd_chunk.seek(0) + dummy = self._ssnd_chunk.read(8) + pos = self._soundpos * self._framesize + if pos: + self._ssnd_chunk.setpos(pos + 8) + self._ssnd_seek_needed = 0 + if nframes == 0: + return '' + data = self._ssnd_chunk.read(nframes * self._framesize) + if self._convert and data: + data = self._convert(data) + self._soundpos = self._soundpos + len(data) / (self._nchannels * self._sampwidth) + return data + + # + # Internal methods. + # + + def _decomp_data(self, data): + import cl + dummy = self._decomp.SetParam(cl.FRAME_BUFFER_SIZE, + len(data) * 2) + return self._decomp.Decompress(len(data) / self._nchannels, + data) + + def _ulaw2lin(self, data): + import audioop + return audioop.ulaw2lin(data, 2) + + def _adpcm2lin(self, data): + import audioop + if not hasattr(self, '_adpcmstate'): + # first time + self._adpcmstate = None + data, self._adpcmstate = audioop.adpcm2lin(data, 2, + self._adpcmstate) + return data + + def _read_comm_chunk(self, chunk): + self._nchannels = _read_short(chunk) + self._nframes = _read_long(chunk) + self._sampwidth = (_read_short(chunk) + 7) / 8 + self._framerate = int(_read_float(chunk)) + self._framesize = self._nchannels * self._sampwidth + if self._aifc: + #DEBUG: SGI's soundeditor produces a bad size :-( + kludge = 0 + if chunk.chunksize == 18: + kludge = 1 + print 'Warning: bad COMM chunk size' + chunk.chunksize = 23 + #DEBUG end + self._comptype = chunk.read(4) + #DEBUG start + if kludge: + length = ord(chunk.file.read(1)) + if length & 1 == 0: + length = length + 1 + chunk.chunksize = chunk.chunksize + length + chunk.file.seek(-1, 1) + #DEBUG end + self._compname = _read_string(chunk) + if self._comptype != 'NONE': + if self._comptype == 'G722': + try: + import audioop + except ImportError: + pass + else: + self._convert = self._adpcm2lin + self._framesize = self._framesize / 4 + return + # for ULAW and ALAW try Compression Library + try: + import cl + except ImportError: + if self._comptype == 'ULAW': + try: + import audioop + self._convert = self._ulaw2lin + self._framesize = self._framesize / 2 + return + except ImportError: + pass + raise Error, 'cannot read compressed AIFF-C files' + if self._comptype == 'ULAW': + scheme = cl.G711_ULAW + self._framesize = self._framesize / 2 + elif self._comptype == 'ALAW': + scheme = cl.G711_ALAW + self._framesize = self._framesize / 2 + else: + raise Error, 'unsupported compression type' + self._decomp = cl.OpenDecompressor(scheme) + self._convert = self._decomp_data + else: + self._comptype = 'NONE' + self._compname = 'not compressed' + + def _readmark(self, chunk): + nmarkers = _read_short(chunk) + # Some files appear to contain invalid counts. + # Cope with this by testing for EOF. + try: + for i in range(nmarkers): + id = _read_short(chunk) + pos = _read_long(chunk) + name = _read_string(chunk) + if pos or name: + # some files appear to have + # dummy markers consisting of + # a position 0 and name '' + self._markers.append((id, pos, name)) + except EOFError: + print 'Warning: MARK chunk contains only', + print len(self._markers), + if len(self._markers) == 1: print 'marker', + else: print 'markers', + print 'instead of', nmarkers class Aifc_write: - # Variables used in this class: - # - # These variables are user settable through appropriate methods - # of this class: - # _file -- the open file with methods write(), close(), tell(), seek() - # set through the __init__() method - # _comptype -- the AIFF-C compression type ('NONE' in AIFF) - # set through the setcomptype() or setparams() method - # _compname -- the human-readable AIFF-C compression type - # set through the setcomptype() or setparams() method - # _nchannels -- the number of audio channels - # set through the setnchannels() or setparams() method - # _sampwidth -- the number of bytes per audio sample - # set through the setsampwidth() or setparams() method - # _framerate -- the sampling frequency - # set through the setframerate() or setparams() method - # _nframes -- the number of audio frames written to the header - # set through the setnframes() or setparams() method - # _aifc -- whether we're writing an AIFF-C file or an AIFF file - # set through the aifc() method, reset through the - # aiff() method - # - # These variables are used internally only: - # _version -- the AIFF-C version number - # _comp -- the compressor from builtin module cl - # _nframeswritten -- the number of audio frames actually written - # _datalength -- the size of the audio samples written to the header - # _datawritten -- the size of the audio samples actually written - - def __init__(self, f): - if type(f) == type(''): - filename = f - f = __builtin__.open(f, 'wb') - else: - # else, assume it is an open file object already - filename = '???' - self.initfp(f) - if filename[-5:] == '.aiff': - self._aifc = 0 - else: - self._aifc = 1 - - def initfp(self, file): - self._file = file - self._version = _AIFC_version - self._comptype = 'NONE' - self._compname = 'not compressed' - self._comp = None - self._convert = None - self._nchannels = 0 - self._sampwidth = 0 - self._framerate = 0 - self._nframes = 0 - self._nframeswritten = 0 - self._datawritten = 0 - self._datalength = 0 - self._markers = [] - self._marklength = 0 - self._aifc = 1 # AIFF-C is default - - def __del__(self): - if self._file: - self.close() - - # - # User visible methods. - # - def aiff(self): - if self._nframeswritten: - raise Error, 'cannot change parameters after starting to write' - self._aifc = 0 - - def aifc(self): - if self._nframeswritten: - raise Error, 'cannot change parameters after starting to write' - self._aifc = 1 - - def setnchannels(self, nchannels): - if self._nframeswritten: - raise Error, 'cannot change parameters after starting to write' - if nchannels < 1: - raise Error, 'bad # of channels' - self._nchannels = nchannels - - def getnchannels(self): - if not self._nchannels: - raise Error, 'number of channels not set' - return self._nchannels - - def setsampwidth(self, sampwidth): - if self._nframeswritten: - raise Error, 'cannot change parameters after starting to write' - if sampwidth < 1 or sampwidth > 4: - raise Error, 'bad sample width' - self._sampwidth = sampwidth - - def getsampwidth(self): - if not self._sampwidth: - raise Error, 'sample width not set' - return self._sampwidth - - def setframerate(self, framerate): - if self._nframeswritten: - raise Error, 'cannot change parameters after starting to write' - if framerate <= 0: - raise Error, 'bad frame rate' - self._framerate = framerate - - def getframerate(self): - if not self._framerate: - raise Error, 'frame rate not set' - return self._framerate - - def setnframes(self, nframes): - if self._nframeswritten: - raise Error, 'cannot change parameters after starting to write' - self._nframes = nframes - - def getnframes(self): - return self._nframeswritten - - def setcomptype(self, comptype, compname): - if self._nframeswritten: - raise Error, 'cannot change parameters after starting to write' - if comptype not in ('NONE', 'ULAW', 'ALAW', 'G722'): - raise Error, 'unsupported compression type' - self._comptype = comptype - self._compname = compname - - def getcomptype(self): - return self._comptype - - def getcompname(self): - return self._compname - -## def setversion(self, version): -## if self._nframeswritten: -## raise Error, 'cannot change parameters after starting to write' -## self._version = version - - def setparams(self, (nchannels, sampwidth, framerate, nframes, comptype, compname)): - if self._nframeswritten: - raise Error, 'cannot change parameters after starting to write' - if comptype not in ('NONE', 'ULAW', 'ALAW', 'G722'): - raise Error, 'unsupported compression type' - self.setnchannels(nchannels) - self.setsampwidth(sampwidth) - self.setframerate(framerate) - self.setnframes(nframes) - self.setcomptype(comptype, compname) - - def getparams(self): - if not self._nchannels or not self._sampwidth or not self._framerate: - raise Error, 'not all parameters set' - return self._nchannels, self._sampwidth, self._framerate, \ - self._nframes, self._comptype, self._compname - - def setmark(self, id, pos, name): - if id <= 0: - raise Error, 'marker ID must be > 0' - if pos < 0: - raise Error, 'marker position must be >= 0' - if type(name) != type(''): - raise Error, 'marker name must be a string' - for i in range(len(self._markers)): - if id == self._markers[i][0]: - self._markers[i] = id, pos, name - return - self._markers.append((id, pos, name)) - - def getmark(self, id): - for marker in self._markers: - if id == marker[0]: - return marker - raise Error, 'marker ' + `id` + ' does not exist' - - def getmarkers(self): - if len(self._markers) == 0: - return None - return self._markers - - def tell(self): - return self._nframeswritten - - def writeframesraw(self, data): - self._ensure_header_written(len(data)) - nframes = len(data) / (self._sampwidth * self._nchannels) - if self._convert: - data = self._convert(data) - self._file.write(data) - self._nframeswritten = self._nframeswritten + nframes - self._datawritten = self._datawritten + len(data) - - def writeframes(self, data): - self.writeframesraw(data) - if self._nframeswritten != self._nframes or \ - self._datalength != self._datawritten: - self._patchheader() - - def close(self): - self._ensure_header_written(0) - if self._datawritten & 1: - # quick pad to even size - self._file.write(chr(0)) - self._datawritten = self._datawritten + 1 - self._writemarkers() - if self._nframeswritten != self._nframes or \ - self._datalength != self._datawritten or \ - self._marklength: - self._patchheader() - if self._comp: - self._comp.CloseCompressor() - self._comp = None - self._file.flush() - self._file = None - - # - # Internal methods. - # - - def _comp_data(self, data): - import cl - dum = self._comp.SetParam(cl.FRAME_BUFFER_SIZE, len(data)) - dum = self._comp.SetParam(cl.COMPRESSED_BUFFER_SIZE, len(data)) - return self._comp.Compress(self._nframes, data) - - def _lin2ulaw(self, data): - import audioop - return audioop.lin2ulaw(data, 2) - - def _lin2adpcm(self, data): - import audioop - if not hasattr(self, '_adpcmstate'): - self._adpcmstate = None - data, self._adpcmstate = audioop.lin2adpcm(data, 2, - self._adpcmstate) - return data - - def _ensure_header_written(self, datasize): - if not self._nframeswritten: - if self._comptype in ('ULAW', 'ALAW'): - if not self._sampwidth: - self._sampwidth = 2 - if self._sampwidth != 2: - raise Error, 'sample width must be 2 when compressing with ULAW or ALAW' - if self._comptype == 'G722': - if not self._sampwidth: - self._sampwidth = 2 - if self._sampwidth != 2: - raise Error, 'sample width must be 2 when compressing with G7.22 (ADPCM)' - if not self._nchannels: - raise Error, '# channels not specified' - if not self._sampwidth: - raise Error, 'sample width not specified' - if not self._framerate: - raise Error, 'sampling rate not specified' - self._write_header(datasize) - - def _init_compression(self): - if self._comptype == 'G722': - import audioop - self._convert = self._lin2adpcm - return - try: - import cl - except ImportError: - if self._comptype == 'ULAW': - try: - import audioop - self._convert = self._lin2ulaw - return - except ImportError: - pass - raise Error, 'cannot write compressed AIFF-C files' - if self._comptype == 'ULAW': - scheme = cl.G711_ULAW - elif self._comptype == 'ALAW': - scheme = cl.G711_ALAW - else: - raise Error, 'unsupported compression type' - self._comp = cl.OpenCompressor(scheme) - params = [cl.ORIGINAL_FORMAT, 0, - cl.BITS_PER_COMPONENT, self._sampwidth * 8, - cl.FRAME_RATE, self._framerate, - cl.FRAME_BUFFER_SIZE, 100, - cl.COMPRESSED_BUFFER_SIZE, 100] - if self._nchannels == 1: - params[1] = cl.MONO - elif self._nchannels == 2: - params[1] = cl.STEREO_INTERLEAVED - else: - raise Error, 'cannot compress more than 2 channels' - self._comp.SetParams(params) - # the compressor produces a header which we ignore - dummy = self._comp.Compress(0, '') - self._convert = self._comp_data - - def _write_header(self, initlength): - if self._aifc and self._comptype != 'NONE': - self._init_compression() - self._file.write('FORM') - if not self._nframes: - self._nframes = initlength / (self._nchannels * self._sampwidth) - self._datalength = self._nframes * self._nchannels * self._sampwidth - if self._datalength & 1: - self._datalength = self._datalength + 1 - if self._aifc: - if self._comptype in ('ULAW', 'ALAW'): - self._datalength = self._datalength / 2 - if self._datalength & 1: - self._datalength = self._datalength + 1 - elif self._comptype == 'G722': - self._datalength = (self._datalength + 3) / 4 - if self._datalength & 1: - self._datalength = self._datalength + 1 - self._form_length_pos = self._file.tell() - commlength = self._write_form_length(self._datalength) - if self._aifc: - self._file.write('AIFC') - self._file.write('FVER') - _write_long(self._file, 4) - _write_long(self._file, self._version) - else: - self._file.write('AIFF') - self._file.write('COMM') - _write_long(self._file, commlength) - _write_short(self._file, self._nchannels) - self._nframes_pos = self._file.tell() - _write_long(self._file, self._nframes) - _write_short(self._file, self._sampwidth * 8) - _write_float(self._file, self._framerate) - if self._aifc: - self._file.write(self._comptype) - _write_string(self._file, self._compname) - self._file.write('SSND') - self._ssnd_length_pos = self._file.tell() - _write_long(self._file, self._datalength + 8) - _write_long(self._file, 0) - _write_long(self._file, 0) - - def _write_form_length(self, datalength): - if self._aifc: - commlength = 18 + 5 + len(self._compname) - if commlength & 1: - commlength = commlength + 1 - verslength = 12 - else: - commlength = 18 - verslength = 0 - _write_long(self._file, 4 + verslength + self._marklength + \ - 8 + commlength + 16 + datalength) - return commlength - - def _patchheader(self): - curpos = self._file.tell() - if self._datawritten & 1: - datalength = self._datawritten + 1 - self._file.write(chr(0)) - else: - datalength = self._datawritten - if datalength == self._datalength and \ - self._nframes == self._nframeswritten and \ - self._marklength == 0: - self._file.seek(curpos, 0) - return - self._file.seek(self._form_length_pos, 0) - dummy = self._write_form_length(datalength) - self._file.seek(self._nframes_pos, 0) - _write_long(self._file, self._nframeswritten) - self._file.seek(self._ssnd_length_pos, 0) - _write_long(self._file, datalength + 8) - self._file.seek(curpos, 0) - self._nframes = self._nframeswritten - self._datalength = datalength - - def _writemarkers(self): - if len(self._markers) == 0: - return - self._file.write('MARK') - length = 2 - for marker in self._markers: - id, pos, name = marker - length = length + len(name) + 1 + 6 - if len(name) & 1 == 0: - length = length + 1 - _write_long(self._file, length) - self._marklength = length + 8 - _write_short(self._file, len(self._markers)) - for marker in self._markers: - id, pos, name = marker - _write_short(self._file, id) - _write_long(self._file, pos) - _write_string(self._file, name) + # Variables used in this class: + # + # These variables are user settable through appropriate methods + # of this class: + # _file -- the open file with methods write(), close(), tell(), seek() + # set through the __init__() method + # _comptype -- the AIFF-C compression type ('NONE' in AIFF) + # set through the setcomptype() or setparams() method + # _compname -- the human-readable AIFF-C compression type + # set through the setcomptype() or setparams() method + # _nchannels -- the number of audio channels + # set through the setnchannels() or setparams() method + # _sampwidth -- the number of bytes per audio sample + # set through the setsampwidth() or setparams() method + # _framerate -- the sampling frequency + # set through the setframerate() or setparams() method + # _nframes -- the number of audio frames written to the header + # set through the setnframes() or setparams() method + # _aifc -- whether we're writing an AIFF-C file or an AIFF file + # set through the aifc() method, reset through the + # aiff() method + # + # These variables are used internally only: + # _version -- the AIFF-C version number + # _comp -- the compressor from builtin module cl + # _nframeswritten -- the number of audio frames actually written + # _datalength -- the size of the audio samples written to the header + # _datawritten -- the size of the audio samples actually written + + def __init__(self, f): + if type(f) == type(''): + filename = f + f = __builtin__.open(f, 'wb') + else: + # else, assume it is an open file object already + filename = '???' + self.initfp(f) + if filename[-5:] == '.aiff': + self._aifc = 0 + else: + self._aifc = 1 + + def initfp(self, file): + self._file = file + self._version = _AIFC_version + self._comptype = 'NONE' + self._compname = 'not compressed' + self._comp = None + self._convert = None + self._nchannels = 0 + self._sampwidth = 0 + self._framerate = 0 + self._nframes = 0 + self._nframeswritten = 0 + self._datawritten = 0 + self._datalength = 0 + self._markers = [] + self._marklength = 0 + self._aifc = 1 # AIFF-C is default + + def __del__(self): + if self._file: + self.close() + + # + # User visible methods. + # + def aiff(self): + if self._nframeswritten: + raise Error, 'cannot change parameters after starting to write' + self._aifc = 0 + + def aifc(self): + if self._nframeswritten: + raise Error, 'cannot change parameters after starting to write' + self._aifc = 1 + + def setnchannels(self, nchannels): + if self._nframeswritten: + raise Error, 'cannot change parameters after starting to write' + if nchannels < 1: + raise Error, 'bad # of channels' + self._nchannels = nchannels + + def getnchannels(self): + if not self._nchannels: + raise Error, 'number of channels not set' + return self._nchannels + + def setsampwidth(self, sampwidth): + if self._nframeswritten: + raise Error, 'cannot change parameters after starting to write' + if sampwidth < 1 or sampwidth > 4: + raise Error, 'bad sample width' + self._sampwidth = sampwidth + + def getsampwidth(self): + if not self._sampwidth: + raise Error, 'sample width not set' + return self._sampwidth + + def setframerate(self, framerate): + if self._nframeswritten: + raise Error, 'cannot change parameters after starting to write' + if framerate <= 0: + raise Error, 'bad frame rate' + self._framerate = framerate + + def getframerate(self): + if not self._framerate: + raise Error, 'frame rate not set' + return self._framerate + + def setnframes(self, nframes): + if self._nframeswritten: + raise Error, 'cannot change parameters after starting to write' + self._nframes = nframes + + def getnframes(self): + return self._nframeswritten + + def setcomptype(self, comptype, compname): + if self._nframeswritten: + raise Error, 'cannot change parameters after starting to write' + if comptype not in ('NONE', 'ULAW', 'ALAW', 'G722'): + raise Error, 'unsupported compression type' + self._comptype = comptype + self._compname = compname + + def getcomptype(self): + return self._comptype + + def getcompname(self): + return self._compname + +## def setversion(self, version): +## if self._nframeswritten: +## raise Error, 'cannot change parameters after starting to write' +## self._version = version + + def setparams(self, (nchannels, sampwidth, framerate, nframes, comptype, compname)): + if self._nframeswritten: + raise Error, 'cannot change parameters after starting to write' + if comptype not in ('NONE', 'ULAW', 'ALAW', 'G722'): + raise Error, 'unsupported compression type' + self.setnchannels(nchannels) + self.setsampwidth(sampwidth) + self.setframerate(framerate) + self.setnframes(nframes) + self.setcomptype(comptype, compname) + + def getparams(self): + if not self._nchannels or not self._sampwidth or not self._framerate: + raise Error, 'not all parameters set' + return self._nchannels, self._sampwidth, self._framerate, \ + self._nframes, self._comptype, self._compname + + def setmark(self, id, pos, name): + if id <= 0: + raise Error, 'marker ID must be > 0' + if pos < 0: + raise Error, 'marker position must be >= 0' + if type(name) != type(''): + raise Error, 'marker name must be a string' + for i in range(len(self._markers)): + if id == self._markers[i][0]: + self._markers[i] = id, pos, name + return + self._markers.append((id, pos, name)) + + def getmark(self, id): + for marker in self._markers: + if id == marker[0]: + return marker + raise Error, 'marker ' + `id` + ' does not exist' + + def getmarkers(self): + if len(self._markers) == 0: + return None + return self._markers + + def tell(self): + return self._nframeswritten + + def writeframesraw(self, data): + self._ensure_header_written(len(data)) + nframes = len(data) / (self._sampwidth * self._nchannels) + if self._convert: + data = self._convert(data) + self._file.write(data) + self._nframeswritten = self._nframeswritten + nframes + self._datawritten = self._datawritten + len(data) + + def writeframes(self, data): + self.writeframesraw(data) + if self._nframeswritten != self._nframes or \ + self._datalength != self._datawritten: + self._patchheader() + + def close(self): + self._ensure_header_written(0) + if self._datawritten & 1: + # quick pad to even size + self._file.write(chr(0)) + self._datawritten = self._datawritten + 1 + self._writemarkers() + if self._nframeswritten != self._nframes or \ + self._datalength != self._datawritten or \ + self._marklength: + self._patchheader() + if self._comp: + self._comp.CloseCompressor() + self._comp = None + self._file.flush() + self._file = None + + # + # Internal methods. + # + + def _comp_data(self, data): + import cl + dum = self._comp.SetParam(cl.FRAME_BUFFER_SIZE, len(data)) + dum = self._comp.SetParam(cl.COMPRESSED_BUFFER_SIZE, len(data)) + return self._comp.Compress(self._nframes, data) + + def _lin2ulaw(self, data): + import audioop + return audioop.lin2ulaw(data, 2) + + def _lin2adpcm(self, data): + import audioop + if not hasattr(self, '_adpcmstate'): + self._adpcmstate = None + data, self._adpcmstate = audioop.lin2adpcm(data, 2, + self._adpcmstate) + return data + + def _ensure_header_written(self, datasize): + if not self._nframeswritten: + if self._comptype in ('ULAW', 'ALAW'): + if not self._sampwidth: + self._sampwidth = 2 + if self._sampwidth != 2: + raise Error, 'sample width must be 2 when compressing with ULAW or ALAW' + if self._comptype == 'G722': + if not self._sampwidth: + self._sampwidth = 2 + if self._sampwidth != 2: + raise Error, 'sample width must be 2 when compressing with G7.22 (ADPCM)' + if not self._nchannels: + raise Error, '# channels not specified' + if not self._sampwidth: + raise Error, 'sample width not specified' + if not self._framerate: + raise Error, 'sampling rate not specified' + self._write_header(datasize) + + def _init_compression(self): + if self._comptype == 'G722': + import audioop + self._convert = self._lin2adpcm + return + try: + import cl + except ImportError: + if self._comptype == 'ULAW': + try: + import audioop + self._convert = self._lin2ulaw + return + except ImportError: + pass + raise Error, 'cannot write compressed AIFF-C files' + if self._comptype == 'ULAW': + scheme = cl.G711_ULAW + elif self._comptype == 'ALAW': + scheme = cl.G711_ALAW + else: + raise Error, 'unsupported compression type' + self._comp = cl.OpenCompressor(scheme) + params = [cl.ORIGINAL_FORMAT, 0, + cl.BITS_PER_COMPONENT, self._sampwidth * 8, + cl.FRAME_RATE, self._framerate, + cl.FRAME_BUFFER_SIZE, 100, + cl.COMPRESSED_BUFFER_SIZE, 100] + if self._nchannels == 1: + params[1] = cl.MONO + elif self._nchannels == 2: + params[1] = cl.STEREO_INTERLEAVED + else: + raise Error, 'cannot compress more than 2 channels' + self._comp.SetParams(params) + # the compressor produces a header which we ignore + dummy = self._comp.Compress(0, '') + self._convert = self._comp_data + + def _write_header(self, initlength): + if self._aifc and self._comptype != 'NONE': + self._init_compression() + self._file.write('FORM') + if not self._nframes: + self._nframes = initlength / (self._nchannels * self._sampwidth) + self._datalength = self._nframes * self._nchannels * self._sampwidth + if self._datalength & 1: + self._datalength = self._datalength + 1 + if self._aifc: + if self._comptype in ('ULAW', 'ALAW'): + self._datalength = self._datalength / 2 + if self._datalength & 1: + self._datalength = self._datalength + 1 + elif self._comptype == 'G722': + self._datalength = (self._datalength + 3) / 4 + if self._datalength & 1: + self._datalength = self._datalength + 1 + self._form_length_pos = self._file.tell() + commlength = self._write_form_length(self._datalength) + if self._aifc: + self._file.write('AIFC') + self._file.write('FVER') + _write_long(self._file, 4) + _write_long(self._file, self._version) + else: + self._file.write('AIFF') + self._file.write('COMM') + _write_long(self._file, commlength) + _write_short(self._file, self._nchannels) + self._nframes_pos = self._file.tell() + _write_long(self._file, self._nframes) + _write_short(self._file, self._sampwidth * 8) + _write_float(self._file, self._framerate) + if self._aifc: + self._file.write(self._comptype) + _write_string(self._file, self._compname) + self._file.write('SSND') + self._ssnd_length_pos = self._file.tell() + _write_long(self._file, self._datalength + 8) + _write_long(self._file, 0) + _write_long(self._file, 0) + + def _write_form_length(self, datalength): + if self._aifc: + commlength = 18 + 5 + len(self._compname) + if commlength & 1: + commlength = commlength + 1 + verslength = 12 + else: + commlength = 18 + verslength = 0 + _write_long(self._file, 4 + verslength + self._marklength + \ + 8 + commlength + 16 + datalength) + return commlength + + def _patchheader(self): + curpos = self._file.tell() + if self._datawritten & 1: + datalength = self._datawritten + 1 + self._file.write(chr(0)) + else: + datalength = self._datawritten + if datalength == self._datalength and \ + self._nframes == self._nframeswritten and \ + self._marklength == 0: + self._file.seek(curpos, 0) + return + self._file.seek(self._form_length_pos, 0) + dummy = self._write_form_length(datalength) + self._file.seek(self._nframes_pos, 0) + _write_long(self._file, self._nframeswritten) + self._file.seek(self._ssnd_length_pos, 0) + _write_long(self._file, datalength + 8) + self._file.seek(curpos, 0) + self._nframes = self._nframeswritten + self._datalength = datalength + + def _writemarkers(self): + if len(self._markers) == 0: + return + self._file.write('MARK') + length = 2 + for marker in self._markers: + id, pos, name = marker + length = length + len(name) + 1 + 6 + if len(name) & 1 == 0: + length = length + 1 + _write_long(self._file, length) + self._marklength = length + 8 + _write_short(self._file, len(self._markers)) + for marker in self._markers: + id, pos, name = marker + _write_short(self._file, id) + _write_long(self._file, pos) + _write_string(self._file, name) def open(f, mode=None): - if mode is None: - if hasattr(f, 'mode'): - mode = f.mode - else: - mode = 'rb' - if mode in ('r', 'rb'): - return Aifc_read(f) - elif mode in ('w', 'wb'): - return Aifc_write(f) - else: - raise Error, "mode must be 'r', 'rb', 'w', or 'wb'" + if mode is None: + if hasattr(f, 'mode'): + mode = f.mode + else: + mode = 'rb' + if mode in ('r', 'rb'): + return Aifc_read(f) + elif mode in ('w', 'wb'): + return Aifc_write(f) + else: + raise Error, "mode must be 'r', 'rb', 'w', or 'wb'" openfp = open # B/W compatibility if __name__ == '__main__': - import sys - if not sys.argv[1:]: - sys.argv.append('/usr/demos/data/audio/bach.aiff') - fn = sys.argv[1] - f = open(fn, 'r') - print "Reading", fn - print "nchannels =", f.getnchannels() - print "nframes =", f.getnframes() - print "sampwidth =", f.getsampwidth() - print "framerate =", f.getframerate() - print "comptype =", f.getcomptype() - print "compname =", f.getcompname() - if sys.argv[2:]: - gn = sys.argv[2] - print "Writing", gn - g = open(gn, 'w') - g.setparams(f.getparams()) - while 1: - data = f.readframes(1024) - if not data: - break - g.writeframes(data) - g.close() - f.close() - print "Done." + import sys + if not sys.argv[1:]: + sys.argv.append('/usr/demos/data/audio/bach.aiff') + fn = sys.argv[1] + f = open(fn, 'r') + print "Reading", fn + print "nchannels =", f.getnchannels() + print "nframes =", f.getnframes() + print "sampwidth =", f.getsampwidth() + print "framerate =", f.getframerate() + print "comptype =", f.getcomptype() + print "compname =", f.getcompname() + if sys.argv[2:]: + gn = sys.argv[2] + print "Writing", gn + g = open(gn, 'w') + g.setparams(f.getparams()) + while 1: + data = f.readframes(1024) + if not data: + break + g.writeframes(data) + g.close() + f.close() + print "Done." diff --git a/Lib/audiodev.py b/Lib/audiodev.py index 83bd6ef..e7cff6c 100644 --- a/Lib/audiodev.py +++ b/Lib/audiodev.py @@ -1,3 +1,5 @@ +"""Classes for manipulating audio devices (currently only for Sun and SGI)""" + error = 'audiodev.error' class Play_Audio_sgi: diff --git a/Lib/base64.py b/Lib/base64.py index 2c72214..5ef2081 100755 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -1,7 +1,7 @@ #! /usr/bin/env python -# Conversions to/from base64 transport encoding as per RFC-1521. -# +"""Conversions to/from base64 transport encoding as per RFC-1521.""" + # Modified 04-Oct-95 by Jack to use binascii module import binascii @@ -9,69 +9,71 @@ import binascii MAXLINESIZE = 76 # Excluding the CRLF MAXBINSIZE = (MAXLINESIZE/4)*3 -# Encode a file. def encode(input, output): - while 1: - s = input.read(MAXBINSIZE) - if not s: break - while len(s) < MAXBINSIZE: - ns = input.read(MAXBINSIZE-len(s)) - if not ns: break - s = s + ns - line = binascii.b2a_base64(s) - output.write(line) + """Encode a file.""" + while 1: + s = input.read(MAXBINSIZE) + if not s: break + while len(s) < MAXBINSIZE: + ns = input.read(MAXBINSIZE-len(s)) + if not ns: break + s = s + ns + line = binascii.b2a_base64(s) + output.write(line) -# Decode a file. def decode(input, output): - while 1: - line = input.readline() - if not line: break - s = binascii.a2b_base64(line) - output.write(s) + """Decode a file.""" + while 1: + line = input.readline() + if not line: break + s = binascii.a2b_base64(line) + output.write(s) def encodestring(s): - import StringIO - f = StringIO.StringIO(s) - g = StringIO.StringIO() - encode(f, g) - return g.getvalue() + """Encode a string.""" + import StringIO + f = StringIO.StringIO(s) + g = StringIO.StringIO() + encode(f, g) + return g.getvalue() def decodestring(s): - import StringIO - f = StringIO.StringIO(s) - g = StringIO.StringIO() - decode(f, g) - return g.getvalue() + """Decode a string.""" + import StringIO + f = StringIO.StringIO(s) + g = StringIO.StringIO() + decode(f, g) + return g.getvalue() -# Small test program def test(): - import sys, getopt - try: - opts, args = getopt.getopt(sys.argv[1:], 'deut') - except getopt.error, msg: - sys.stdout = sys.stderr - print msg - print """usage: basd64 [-d] [-e] [-u] [-t] [file|-] - -d, -u: decode - -e: encode (default) - -t: decode string 'Aladdin:open sesame'""" - sys.exit(2) - func = encode - for o, a in opts: - if o == '-e': func = encode - if o == '-d': func = decode - if o == '-u': func = decode - if o == '-t': test1(); return - if args and args[0] != '-': - func(open(args[0], 'rb'), sys.stdout) - else: - func(sys.stdin, sys.stdout) + """Small test program""" + import sys, getopt + try: + opts, args = getopt.getopt(sys.argv[1:], 'deut') + except getopt.error, msg: + sys.stdout = sys.stderr + print msg + print """usage: basd64 [-d] [-e] [-u] [-t] [file|-] + -d, -u: decode + -e: encode (default) + -t: decode string 'Aladdin:open sesame'""" + sys.exit(2) + func = encode + for o, a in opts: + if o == '-e': func = encode + if o == '-d': func = decode + if o == '-u': func = decode + if o == '-t': test1(); return + if args and args[0] != '-': + func(open(args[0], 'rb'), sys.stdout) + else: + func(sys.stdin, sys.stdout) def test1(): - s0 = "Aladdin:open sesame" - s1 = encodestring(s0) - s2 = decodestring(s1) - print s0, `s1`, s2 + s0 = "Aladdin:open sesame" + s1 = encodestring(s0) + s2 = decodestring(s1) + print s0, `s1`, s2 if __name__ == '__main__': - test() + test() @@ -1,4 +1,4 @@ -# Debugger basics +"""Debugger basics""" import sys import os @@ -8,551 +8,551 @@ BdbQuit = 'bdb.BdbQuit' # Exception to give up completely class Bdb: - - """Generic Python debugger base class. - - This class takes care of details of the trace facility; - a derived class should implement user interaction. - The standard debugger class (pdb.Pdb) is an example. - """ - - def __init__(self): - self.breaks = {} - self.fncache = {} - - def canonic(self, filename): - canonic = self.fncache.get(filename) - if not canonic: - canonic = os.path.abspath(filename) - self.fncache[filename] = canonic - return canonic - - def reset(self): - import linecache - linecache.checkcache() - self.botframe = None - self.stopframe = None - self.returnframe = None - self.quitting = 0 - - def trace_dispatch(self, frame, event, arg): - if self.quitting: - return # None - if event == 'line': - return self.dispatch_line(frame) - if event == 'call': - return self.dispatch_call(frame, arg) - if event == 'return': - return self.dispatch_return(frame, arg) - if event == 'exception': - return self.dispatch_exception(frame, arg) - print 'bdb.Bdb.dispatch: unknown debugging event:', `event` - return self.trace_dispatch - - def dispatch_line(self, frame): - if self.stop_here(frame) or self.break_here(frame): - self.user_line(frame) - if self.quitting: raise BdbQuit - return self.trace_dispatch - - def dispatch_call(self, frame, arg): - # XXX 'arg' is no longer used - if self.botframe is None: - # First call of dispatch since reset() - self.botframe = frame - return self.trace_dispatch - if not (self.stop_here(frame) or self.break_anywhere(frame)): - # No need to trace this function - return # None - self.user_call(frame, arg) - if self.quitting: raise BdbQuit - return self.trace_dispatch - - def dispatch_return(self, frame, arg): - if self.stop_here(frame) or frame == self.returnframe: - self.user_return(frame, arg) - if self.quitting: raise BdbQuit - - def dispatch_exception(self, frame, arg): - if self.stop_here(frame): - self.user_exception(frame, arg) - if self.quitting: raise BdbQuit - return self.trace_dispatch - - # Normally derived classes don't override the following - # methods, but they may if they want to redefine the - # definition of stopping and breakpoints. - - def stop_here(self, frame): - if self.stopframe is None: - return 1 - if frame is self.stopframe: - return 1 - while frame is not None and frame is not self.stopframe: - if frame is self.botframe: - return 1 - frame = frame.f_back - return 0 - - def break_here(self, frame): - filename = self.canonic(frame.f_code.co_filename) - if not self.breaks.has_key(filename): - return 0 - lineno = frame.f_lineno - if not lineno in self.breaks[filename]: - return 0 - # flag says ok to delete temp. bp - (bp, flag) = effective(filename, lineno, frame) - if bp: - self.currentbp = bp.number - if (flag and bp.temporary): - self.do_clear(str(bp.number)) - return 1 - else: - return 0 - - def break_anywhere(self, frame): - return self.breaks.has_key( - self.canonic(frame.f_code.co_filename)) - - # Derived classes should override the user_* methods - # to gain control. - - def user_call(self, frame, argument_list): - # This method is called when there is the remote possibility - # that we ever need to stop in this function - pass - - def user_line(self, frame): - # This method is called when we stop or break at this line - pass - - def user_return(self, frame, return_value): - # This method is called when a return trap is set here - pass - - def user_exception(self, frame, (exc_type, exc_value, exc_traceback)): - # This method is called if an exception occurs, - # but only if we are to stop at or just below this level - pass - - # Derived classes and clients can call the following methods - # to affect the stepping state. - - def set_step(self): - # Stop after one line of code - self.stopframe = None - self.returnframe = None - self.quitting = 0 - - def set_next(self, frame): - # Stop on the next line in or below the given frame - self.stopframe = frame - self.returnframe = None - self.quitting = 0 - - def set_return(self, frame): - # Stop when returning from the given frame - self.stopframe = frame.f_back - self.returnframe = frame - self.quitting = 0 - - def set_trace(self): - # Start debugging from here - try: - 1 + '' - except: - frame = sys.exc_info()[2].tb_frame.f_back - self.reset() - while frame: - frame.f_trace = self.trace_dispatch - self.botframe = frame - frame = frame.f_back - self.set_step() - sys.settrace(self.trace_dispatch) - - def set_continue(self): - # Don't stop except at breakpoints or when finished - self.stopframe = self.botframe - self.returnframe = None - self.quitting = 0 - if not self.breaks: - # no breakpoints; run without debugger overhead - sys.settrace(None) - try: - 1 + '' # raise an exception - except: - frame = sys.exc_info()[2].tb_frame.f_back - while frame and frame is not self.botframe: - del frame.f_trace - frame = frame.f_back - - def set_quit(self): - self.stopframe = self.botframe - self.returnframe = None - self.quitting = 1 - sys.settrace(None) - - # Derived classes and clients can call the following methods - # to manipulate breakpoints. These methods return an - # error message is something went wrong, None if all is well. - # Set_break prints out the breakpoint line and file:lineno. - # Call self.get_*break*() to see the breakpoints or better - # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint(). - - def set_break(self, filename, lineno, temporary=0, cond = None): - filename = self.canonic(filename) - import linecache # Import as late as possible - line = linecache.getline(filename, lineno) - if not line: - return 'Line %s:%d does not exist' % (filename, - lineno) - if not self.breaks.has_key(filename): - self.breaks[filename] = [] - list = self.breaks[filename] - if not lineno in list: - list.append(lineno) - bp = Breakpoint(filename, lineno, temporary, cond) - - def clear_break(self, filename, lineno): - filename = self.canonic(filename) - if not self.breaks.has_key(filename): - return 'There are no breakpoints in %s' % filename - if lineno not in self.breaks[filename]: - return 'There is no breakpoint at %s:%d' % (filename, - lineno) - # If there's only one bp in the list for that file,line - # pair, then remove the breaks entry - for bp in Breakpoint.bplist[filename, lineno][:]: - bp.deleteMe() - if not Breakpoint.bplist.has_key((filename, lineno)): - self.breaks[filename].remove(lineno) - if not self.breaks[filename]: - del self.breaks[filename] - - def clear_bpbynumber(self, arg): - try: - number = int(arg) - except: - return 'Non-numeric breakpoint number (%s)' % arg - try: - bp = Breakpoint.bpbynumber[number] - except IndexError: - return 'Breakpoint number (%d) out of range' % number - if not bp: - return 'Breakpoint (%d) already deleted' % number - self.clear_break(bp.file, bp.line) - - def clear_all_file_breaks(self, filename): - filename = self.canonic(filename) - if not self.breaks.has_key(filename): - return 'There are no breakpoints in %s' % filename - for line in self.breaks[filename]: - blist = Breakpoint.bplist[filename, line] - for bp in blist: - bp.deleteMe() - del self.breaks[filename] - - def clear_all_breaks(self): - if not self.breaks: - return 'There are no breakpoints' - for bp in Breakpoint.bpbynumber: - if bp: - bp.deleteMe() - self.breaks = {} - - def get_break(self, filename, lineno): - filename = self.canonic(filename) - return self.breaks.has_key(filename) and \ - lineno in self.breaks[filename] - - def get_breaks(self, filename, lineno): - filename = self.canonic(filename) - return self.breaks.has_key(filename) and \ - lineno in self.breaks[filename] and \ - Breakpoint.bplist[filename, lineno] or [] - - def get_file_breaks(self, filename): - filename = self.canonic(filename) - if self.breaks.has_key(filename): - return self.breaks[filename] - else: - return [] - - def get_all_breaks(self): - return self.breaks - - # Derived classes and clients can call the following method - # to get a data structure representing a stack trace. - - def get_stack(self, f, t): - stack = [] - if t and t.tb_frame is f: - t = t.tb_next - while f is not None: - stack.append((f, f.f_lineno)) - if f is self.botframe: - break - f = f.f_back - stack.reverse() - i = max(0, len(stack) - 1) - while t is not None: - stack.append((t.tb_frame, t.tb_lineno)) - t = t.tb_next - return stack, i - - # - - def format_stack_entry(self, frame_lineno, lprefix=': '): - import linecache, repr, string - frame, lineno = frame_lineno - filename = self.canonic(frame.f_code.co_filename) - s = filename + '(' + `lineno` + ')' - if frame.f_code.co_name: - s = s + frame.f_code.co_name - else: - s = s + "<lambda>" - if frame.f_locals.has_key('__args__'): - args = frame.f_locals['__args__'] - else: - args = None - if args: - s = s + repr.repr(args) - else: - s = s + '()' - if frame.f_locals.has_key('__return__'): - rv = frame.f_locals['__return__'] - s = s + '->' - s = s + repr.repr(rv) - line = linecache.getline(filename, lineno) - if line: s = s + lprefix + string.strip(line) - return s - - # The following two methods can be called by clients to use - # a debugger to debug a statement, given as a string. - - def run(self, cmd, globals=None, locals=None): - if globals is None: - import __main__ - globals = __main__.__dict__ - if locals is None: - locals = globals - self.reset() - sys.settrace(self.trace_dispatch) - if not isinstance(cmd, types.CodeType): - cmd = cmd+'\n' - try: - try: - exec cmd in globals, locals - except BdbQuit: - pass - finally: - self.quitting = 1 - sys.settrace(None) - - def runeval(self, expr, globals=None, locals=None): - if globals is None: - import __main__ - globals = __main__.__dict__ - if locals is None: - locals = globals - self.reset() - sys.settrace(self.trace_dispatch) - if not isinstance(expr, types.CodeType): - expr = expr+'\n' - try: - try: - return eval(expr, globals, locals) - except BdbQuit: - pass - finally: - self.quitting = 1 - sys.settrace(None) - - def runctx(self, cmd, globals, locals): - # B/W compatibility - self.run(cmd, globals, locals) - - # This method is more useful to debug a single function call. - - def runcall(self, func, *args): - self.reset() - sys.settrace(self.trace_dispatch) - res = None - try: - try: - res = apply(func, args) - except BdbQuit: - pass - finally: - self.quitting = 1 - sys.settrace(None) - return res + + """Generic Python debugger base class. + + This class takes care of details of the trace facility; + a derived class should implement user interaction. + The standard debugger class (pdb.Pdb) is an example. + """ + + def __init__(self): + self.breaks = {} + self.fncache = {} + + def canonic(self, filename): + canonic = self.fncache.get(filename) + if not canonic: + canonic = os.path.abspath(filename) + self.fncache[filename] = canonic + return canonic + + def reset(self): + import linecache + linecache.checkcache() + self.botframe = None + self.stopframe = None + self.returnframe = None + self.quitting = 0 + + def trace_dispatch(self, frame, event, arg): + if self.quitting: + return # None + if event == 'line': + return self.dispatch_line(frame) + if event == 'call': + return self.dispatch_call(frame, arg) + if event == 'return': + return self.dispatch_return(frame, arg) + if event == 'exception': + return self.dispatch_exception(frame, arg) + print 'bdb.Bdb.dispatch: unknown debugging event:', `event` + return self.trace_dispatch + + def dispatch_line(self, frame): + if self.stop_here(frame) or self.break_here(frame): + self.user_line(frame) + if self.quitting: raise BdbQuit + return self.trace_dispatch + + def dispatch_call(self, frame, arg): + # XXX 'arg' is no longer used + if self.botframe is None: + # First call of dispatch since reset() + self.botframe = frame + return self.trace_dispatch + if not (self.stop_here(frame) or self.break_anywhere(frame)): + # No need to trace this function + return # None + self.user_call(frame, arg) + if self.quitting: raise BdbQuit + return self.trace_dispatch + + def dispatch_return(self, frame, arg): + if self.stop_here(frame) or frame == self.returnframe: + self.user_return(frame, arg) + if self.quitting: raise BdbQuit + + def dispatch_exception(self, frame, arg): + if self.stop_here(frame): + self.user_exception(frame, arg) + if self.quitting: raise BdbQuit + return self.trace_dispatch + + # Normally derived classes don't override the following + # methods, but they may if they want to redefine the + # definition of stopping and breakpoints. + + def stop_here(self, frame): + if self.stopframe is None: + return 1 + if frame is self.stopframe: + return 1 + while frame is not None and frame is not self.stopframe: + if frame is self.botframe: + return 1 + frame = frame.f_back + return 0 + + def break_here(self, frame): + filename = self.canonic(frame.f_code.co_filename) + if not self.breaks.has_key(filename): + return 0 + lineno = frame.f_lineno + if not lineno in self.breaks[filename]: + return 0 + # flag says ok to delete temp. bp + (bp, flag) = effective(filename, lineno, frame) + if bp: + self.currentbp = bp.number + if (flag and bp.temporary): + self.do_clear(str(bp.number)) + return 1 + else: + return 0 + + def break_anywhere(self, frame): + return self.breaks.has_key( + self.canonic(frame.f_code.co_filename)) + + # Derived classes should override the user_* methods + # to gain control. + + def user_call(self, frame, argument_list): + """This method is called when there is the remote possibility + that we ever need to stop in this function.""" + pass + + def user_line(self, frame): + """This method is called when we stop or break at this line.""" + pass + + def user_return(self, frame, return_value): + """This method is called when a return trap is set here.""" + pass + + def user_exception(self, frame, (exc_type, exc_value, exc_traceback)): + """This method is called if an exception occurs, + but only if we are to stop at or just below this level.""" + pass + + # Derived classes and clients can call the following methods + # to affect the stepping state. + + def set_step(self): + """Stop after one line of code.""" + self.stopframe = None + self.returnframe = None + self.quitting = 0 + + def set_next(self, frame): + """Stop on the next line in or below the given frame.""" + self.stopframe = frame + self.returnframe = None + self.quitting = 0 + + def set_return(self, frame): + """Stop when returning from the given frame.""" + self.stopframe = frame.f_back + self.returnframe = frame + self.quitting = 0 + + def set_trace(self): + """Start debugging from here.""" + try: + 1 + '' + except: + frame = sys.exc_info()[2].tb_frame.f_back + self.reset() + while frame: + frame.f_trace = self.trace_dispatch + self.botframe = frame + frame = frame.f_back + self.set_step() + sys.settrace(self.trace_dispatch) + + def set_continue(self): + # Don't stop except at breakpoints or when finished + self.stopframe = self.botframe + self.returnframe = None + self.quitting = 0 + if not self.breaks: + # no breakpoints; run without debugger overhead + sys.settrace(None) + try: + 1 + '' # raise an exception + except: + frame = sys.exc_info()[2].tb_frame.f_back + while frame and frame is not self.botframe: + del frame.f_trace + frame = frame.f_back + + def set_quit(self): + self.stopframe = self.botframe + self.returnframe = None + self.quitting = 1 + sys.settrace(None) + + # Derived classes and clients can call the following methods + # to manipulate breakpoints. These methods return an + # error message is something went wrong, None if all is well. + # Set_break prints out the breakpoint line and file:lineno. + # Call self.get_*break*() to see the breakpoints or better + # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint(). + + def set_break(self, filename, lineno, temporary=0, cond = None): + filename = self.canonic(filename) + import linecache # Import as late as possible + line = linecache.getline(filename, lineno) + if not line: + return 'Line %s:%d does not exist' % (filename, + lineno) + if not self.breaks.has_key(filename): + self.breaks[filename] = [] + list = self.breaks[filename] + if not lineno in list: + list.append(lineno) + bp = Breakpoint(filename, lineno, temporary, cond) + + def clear_break(self, filename, lineno): + filename = self.canonic(filename) + if not self.breaks.has_key(filename): + return 'There are no breakpoints in %s' % filename + if lineno not in self.breaks[filename]: + return 'There is no breakpoint at %s:%d' % (filename, + lineno) + # If there's only one bp in the list for that file,line + # pair, then remove the breaks entry + for bp in Breakpoint.bplist[filename, lineno][:]: + bp.deleteMe() + if not Breakpoint.bplist.has_key((filename, lineno)): + self.breaks[filename].remove(lineno) + if not self.breaks[filename]: + del self.breaks[filename] + + def clear_bpbynumber(self, arg): + try: + number = int(arg) + except: + return 'Non-numeric breakpoint number (%s)' % arg + try: + bp = Breakpoint.bpbynumber[number] + except IndexError: + return 'Breakpoint number (%d) out of range' % number + if not bp: + return 'Breakpoint (%d) already deleted' % number + self.clear_break(bp.file, bp.line) + + def clear_all_file_breaks(self, filename): + filename = self.canonic(filename) + if not self.breaks.has_key(filename): + return 'There are no breakpoints in %s' % filename + for line in self.breaks[filename]: + blist = Breakpoint.bplist[filename, line] + for bp in blist: + bp.deleteMe() + del self.breaks[filename] + + def clear_all_breaks(self): + if not self.breaks: + return 'There are no breakpoints' + for bp in Breakpoint.bpbynumber: + if bp: + bp.deleteMe() + self.breaks = {} + + def get_break(self, filename, lineno): + filename = self.canonic(filename) + return self.breaks.has_key(filename) and \ + lineno in self.breaks[filename] + + def get_breaks(self, filename, lineno): + filename = self.canonic(filename) + return self.breaks.has_key(filename) and \ + lineno in self.breaks[filename] and \ + Breakpoint.bplist[filename, lineno] or [] + + def get_file_breaks(self, filename): + filename = self.canonic(filename) + if self.breaks.has_key(filename): + return self.breaks[filename] + else: + return [] + + def get_all_breaks(self): + return self.breaks + + # Derived classes and clients can call the following method + # to get a data structure representing a stack trace. + + def get_stack(self, f, t): + stack = [] + if t and t.tb_frame is f: + t = t.tb_next + while f is not None: + stack.append((f, f.f_lineno)) + if f is self.botframe: + break + f = f.f_back + stack.reverse() + i = max(0, len(stack) - 1) + while t is not None: + stack.append((t.tb_frame, t.tb_lineno)) + t = t.tb_next + return stack, i + + # + + def format_stack_entry(self, frame_lineno, lprefix=': '): + import linecache, repr, string + frame, lineno = frame_lineno + filename = self.canonic(frame.f_code.co_filename) + s = filename + '(' + `lineno` + ')' + if frame.f_code.co_name: + s = s + frame.f_code.co_name + else: + s = s + "<lambda>" + if frame.f_locals.has_key('__args__'): + args = frame.f_locals['__args__'] + else: + args = None + if args: + s = s + repr.repr(args) + else: + s = s + '()' + if frame.f_locals.has_key('__return__'): + rv = frame.f_locals['__return__'] + s = s + '->' + s = s + repr.repr(rv) + line = linecache.getline(filename, lineno) + if line: s = s + lprefix + string.strip(line) + return s + + # The following two methods can be called by clients to use + # a debugger to debug a statement, given as a string. + + def run(self, cmd, globals=None, locals=None): + if globals is None: + import __main__ + globals = __main__.__dict__ + if locals is None: + locals = globals + self.reset() + sys.settrace(self.trace_dispatch) + if not isinstance(cmd, types.CodeType): + cmd = cmd+'\n' + try: + try: + exec cmd in globals, locals + except BdbQuit: + pass + finally: + self.quitting = 1 + sys.settrace(None) + + def runeval(self, expr, globals=None, locals=None): + if globals is None: + import __main__ + globals = __main__.__dict__ + if locals is None: + locals = globals + self.reset() + sys.settrace(self.trace_dispatch) + if not isinstance(expr, types.CodeType): + expr = expr+'\n' + try: + try: + return eval(expr, globals, locals) + except BdbQuit: + pass + finally: + self.quitting = 1 + sys.settrace(None) + + def runctx(self, cmd, globals, locals): + # B/W compatibility + self.run(cmd, globals, locals) + + # This method is more useful to debug a single function call. + + def runcall(self, func, *args): + self.reset() + sys.settrace(self.trace_dispatch) + res = None + try: + try: + res = apply(func, args) + except BdbQuit: + pass + finally: + self.quitting = 1 + sys.settrace(None) + return res def set_trace(): - Bdb().set_trace() + Bdb().set_trace() class Breakpoint: - """Breakpoint class - - Implements temporary breakpoints, ignore counts, disabling and - (re)-enabling, and conditionals. - - Breakpoints are indexed by number through bpbynumber and by - the file,line tuple using bplist. The former points to a - single instance of class Breakpoint. The latter points to a - list of such instances since there may be more than one - breakpoint per line. - - """ - - # XXX Keeping state in the class is a mistake -- this means - # you cannot have more than one active Bdb instance. - - next = 1 # Next bp to be assigned - bplist = {} # indexed by (file, lineno) tuple - bpbynumber = [None] # Each entry is None or an instance of Bpt - # index 0 is unused, except for marking an - # effective break .... see effective() - - def __init__(self, file, line, temporary=0, cond = None): - self.file = file # This better be in canonical form! - self.line = line - self.temporary = temporary - self.cond = cond - self.enabled = 1 - self.ignore = 0 - self.hits = 0 - self.number = Breakpoint.next - Breakpoint.next = Breakpoint.next + 1 - # Build the two lists - self.bpbynumber.append(self) - if self.bplist.has_key((file, line)): - self.bplist[file, line].append(self) - else: - self.bplist[file, line] = [self] - - - def deleteMe(self): - index = (self.file, self.line) - self.bpbynumber[self.number] = None # No longer in list - self.bplist[index].remove(self) - if not self.bplist[index]: - # No more bp for this f:l combo - del self.bplist[index] - - def enable(self): - self.enabled = 1 - - def disable(self): - self.enabled = 0 - - def bpprint(self): - if self.temporary: - disp = 'del ' - else: - disp = 'keep ' - if self.enabled: - disp = disp + 'yes' - else: - disp = disp + 'no ' - print '%-4dbreakpoint %s at %s:%d' % (self.number, disp, - self.file, self.line) - if self.cond: - print '\tstop only if %s' % (self.cond,) - if self.ignore: - print '\tignore next %d hits' % (self.ignore) - if (self.hits): - if (self.hits > 1): ss = 's' - else: ss = '' - print ('\tbreakpoint already hit %d time%s' % - (self.hits, ss)) + """Breakpoint class + + Implements temporary breakpoints, ignore counts, disabling and + (re)-enabling, and conditionals. + + Breakpoints are indexed by number through bpbynumber and by + the file,line tuple using bplist. The former points to a + single instance of class Breakpoint. The latter points to a + list of such instances since there may be more than one + breakpoint per line. + + """ + + # XXX Keeping state in the class is a mistake -- this means + # you cannot have more than one active Bdb instance. + + next = 1 # Next bp to be assigned + bplist = {} # indexed by (file, lineno) tuple + bpbynumber = [None] # Each entry is None or an instance of Bpt + # index 0 is unused, except for marking an + # effective break .... see effective() + + def __init__(self, file, line, temporary=0, cond = None): + self.file = file # This better be in canonical form! + self.line = line + self.temporary = temporary + self.cond = cond + self.enabled = 1 + self.ignore = 0 + self.hits = 0 + self.number = Breakpoint.next + Breakpoint.next = Breakpoint.next + 1 + # Build the two lists + self.bpbynumber.append(self) + if self.bplist.has_key((file, line)): + self.bplist[file, line].append(self) + else: + self.bplist[file, line] = [self] + + + def deleteMe(self): + index = (self.file, self.line) + self.bpbynumber[self.number] = None # No longer in list + self.bplist[index].remove(self) + if not self.bplist[index]: + # No more bp for this f:l combo + del self.bplist[index] + + def enable(self): + self.enabled = 1 + + def disable(self): + self.enabled = 0 + + def bpprint(self): + if self.temporary: + disp = 'del ' + else: + disp = 'keep ' + if self.enabled: + disp = disp + 'yes' + else: + disp = disp + 'no ' + print '%-4dbreakpoint %s at %s:%d' % (self.number, disp, + self.file, self.line) + if self.cond: + print '\tstop only if %s' % (self.cond,) + if self.ignore: + print '\tignore next %d hits' % (self.ignore) + if (self.hits): + if (self.hits > 1): ss = 's' + else: ss = '' + print ('\tbreakpoint already hit %d time%s' % + (self.hits, ss)) # -----------end of Breakpoint class---------- # Determines if there is an effective (active) breakpoint at this # line of code. Returns breakpoint number or 0 if none def effective(file, line, frame): - """Determine which breakpoint for this file:line is to be acted upon. - - Called only if we know there is a bpt at this - location. Returns breakpoint that was triggered and a flag - that indicates if it is ok to delete a temporary bp. - - """ - possibles = Breakpoint.bplist[file,line] - for i in range(0, len(possibles)): - b = possibles[i] - if b.enabled == 0: - continue - # Count every hit when bp is enabled - b.hits = b.hits + 1 - if not b.cond: - # If unconditional, and ignoring, - # go on to next, else break - if b.ignore > 0: - b.ignore = b.ignore -1 - continue - else: - # breakpoint and marker that's ok - # to delete if temporary - return (b,1) - else: - # Conditional bp. - # Ignore count applies only to those bpt hits where the - # condition evaluates to true. - try: - val = eval(b.cond, frame.f_globals, - frame.f_locals) - if val: - if b.ignore > 0: - b.ignore = b.ignore -1 - # continue - else: - return (b,1) - # else: - # continue - except: - # if eval fails, most conservative - # thing is to stop on breakpoint - # regardless of ignore count. - # Don't delete temporary, - # as another hint to user. - return (b,0) - return (None, None) + """Determine which breakpoint for this file:line is to be acted upon. + + Called only if we know there is a bpt at this + location. Returns breakpoint that was triggered and a flag + that indicates if it is ok to delete a temporary bp. + + """ + possibles = Breakpoint.bplist[file,line] + for i in range(0, len(possibles)): + b = possibles[i] + if b.enabled == 0: + continue + # Count every hit when bp is enabled + b.hits = b.hits + 1 + if not b.cond: + # If unconditional, and ignoring, + # go on to next, else break + if b.ignore > 0: + b.ignore = b.ignore -1 + continue + else: + # breakpoint and marker that's ok + # to delete if temporary + return (b,1) + else: + # Conditional bp. + # Ignore count applies only to those bpt hits where the + # condition evaluates to true. + try: + val = eval(b.cond, frame.f_globals, + frame.f_locals) + if val: + if b.ignore > 0: + b.ignore = b.ignore -1 + # continue + else: + return (b,1) + # else: + # continue + except: + # if eval fails, most conservative + # thing is to stop on breakpoint + # regardless of ignore count. + # Don't delete temporary, + # as another hint to user. + return (b,0) + return (None, None) # -------------------- testing -------------------- class Tdb(Bdb): - def user_call(self, frame, args): - name = frame.f_code.co_name - if not name: name = '???' - print '+++ call', name, args - def user_line(self, frame): - import linecache, string - name = frame.f_code.co_name - if not name: name = '???' - fn = self.canonic(frame.f_code.co_filename) - line = linecache.getline(fn, frame.f_lineno) - print '+++', fn, frame.f_lineno, name, ':', string.strip(line) - def user_return(self, frame, retval): - print '+++ return', retval - def user_exception(self, frame, exc_stuff): - print '+++ exception', exc_stuff - self.set_continue() + def user_call(self, frame, args): + name = frame.f_code.co_name + if not name: name = '???' + print '+++ call', name, args + def user_line(self, frame): + import linecache, string + name = frame.f_code.co_name + if not name: name = '???' + fn = self.canonic(frame.f_code.co_filename) + line = linecache.getline(fn, frame.f_lineno) + print '+++', fn, frame.f_lineno, name, ':', string.strip(line) + def user_return(self, frame, retval): + print '+++ return', retval + def user_exception(self, frame, exc_stuff): + print '+++ exception', exc_stuff + self.set_continue() def foo(n): - print 'foo(', n, ')' - x = bar(n*10) - print 'bar returned', x + print 'foo(', n, ')' + x = bar(n*10) + print 'bar returned', x def bar(a): - print 'bar(', a, ')' - return a/2 + print 'bar(', a, ')' + return a/2 def test(): - t = Tdb() - t.run('import bdb; bdb.foo(10)') + t = Tdb() + t.run('import bdb; bdb.foo(10)') diff --git a/Lib/binhex.py b/Lib/binhex.py index 92ff4e4..3fc7234 100644 --- a/Lib/binhex.py +++ b/Lib/binhex.py @@ -1,4 +1,5 @@ """binhex - Macintosh binhex compression/decompression + easy interface: binhex(inputfilename, outputfilename) hexbin(inputfilename, outputfilename) @@ -25,16 +26,16 @@ import os import struct import string import binascii - + Error = 'binhex.Error' # States (what have we written) [_DID_HEADER, _DID_DATA, _DID_RSRC] = range(3) # Various constants -REASONABLY_LARGE=32768 # Minimal amount we pass the rle-coder +REASONABLY_LARGE=32768 # Minimal amount we pass the rle-coder LINELEN=64 -RUNCHAR=chr(0x90) # run-length introducer +RUNCHAR=chr(0x90) # run-length introducer # # This code is no longer byte-order dependent @@ -42,488 +43,488 @@ RUNCHAR=chr(0x90) # run-length introducer # # Workarounds for non-mac machines. if os.name == 'mac': - import macfs - import MacOS - try: - openrf = MacOS.openrf - except AttributeError: - # Backward compatability - openrf = open - - def FInfo(): - return macfs.FInfo() - - def getfileinfo(name): - finfo = macfs.FSSpec(name).GetFInfo() - dir, file = os.path.split(name) - # XXXX Get resource/data sizes - fp = open(name, 'rb') - fp.seek(0, 2) - dlen = fp.tell() - fp = openrf(name, '*rb') - fp.seek(0, 2) - rlen = fp.tell() - return file, finfo, dlen, rlen - - def openrsrc(name, *mode): - if not mode: - mode = '*rb' - else: - mode = '*' + mode[0] - return openrf(name, mode) + import macfs + import MacOS + try: + openrf = MacOS.openrf + except AttributeError: + # Backward compatability + openrf = open + + def FInfo(): + return macfs.FInfo() + + def getfileinfo(name): + finfo = macfs.FSSpec(name).GetFInfo() + dir, file = os.path.split(name) + # XXXX Get resource/data sizes + fp = open(name, 'rb') + fp.seek(0, 2) + dlen = fp.tell() + fp = openrf(name, '*rb') + fp.seek(0, 2) + rlen = fp.tell() + return file, finfo, dlen, rlen + + def openrsrc(name, *mode): + if not mode: + mode = '*rb' + else: + mode = '*' + mode[0] + return openrf(name, mode) else: - # - # Glue code for non-macintosh useage - # - - class FInfo: - def __init__(self): - self.Type = '????' - self.Creator = '????' - self.Flags = 0 - - def getfileinfo(name): - finfo = FInfo() - # Quick check for textfile - fp = open(name) - data = open(name).read(256) - for c in data: - if not c in string.whitespace \ - and (c<' ' or ord(c) > 0177): - break - else: - finfo.Type = 'TEXT' - fp.seek(0, 2) - dsize = fp.tell() - fp.close() - dir, file = os.path.split(name) - file = string.replace(file, ':', '-', 1) - return file, finfo, dsize, 0 - - class openrsrc: - def __init__(self, *args): - pass - - def read(self, *args): - return '' - - def write(self, *args): - pass - - def close(self): - pass - + # + # Glue code for non-macintosh useage + # + + class FInfo: + def __init__(self): + self.Type = '????' + self.Creator = '????' + self.Flags = 0 + + def getfileinfo(name): + finfo = FInfo() + # Quick check for textfile + fp = open(name) + data = open(name).read(256) + for c in data: + if not c in string.whitespace \ + and (c<' ' or ord(c) > 0177): + break + else: + finfo.Type = 'TEXT' + fp.seek(0, 2) + dsize = fp.tell() + fp.close() + dir, file = os.path.split(name) + file = string.replace(file, ':', '-', 1) + return file, finfo, dsize, 0 + + class openrsrc: + def __init__(self, *args): + pass + + def read(self, *args): + return '' + + def write(self, *args): + pass + + def close(self): + pass + class _Hqxcoderengine: - """Write data to the coder in 3-byte chunks""" - - def __init__(self, ofp): - self.ofp = ofp - self.data = '' - self.hqxdata = '' - self.linelen = LINELEN-1 - - def write(self, data): - self.data = self.data + data - datalen = len(self.data) - todo = (datalen/3)*3 - data = self.data[:todo] - self.data = self.data[todo:] - if not data: - return - self.hqxdata = self.hqxdata + binascii.b2a_hqx(data) - self._flush(0) - - def _flush(self, force): - first = 0 - while first <= len(self.hqxdata)-self.linelen: - last = first + self.linelen - self.ofp.write(self.hqxdata[first:last]+'\n') - self.linelen = LINELEN - first = last - self.hqxdata = self.hqxdata[first:] - if force: - self.ofp.write(self.hqxdata + ':\n') - - def close(self): - if self.data: - self.hqxdata = \ - self.hqxdata + binascii.b2a_hqx(self.data) - self._flush(1) - self.ofp.close() - del self.ofp + """Write data to the coder in 3-byte chunks""" + + def __init__(self, ofp): + self.ofp = ofp + self.data = '' + self.hqxdata = '' + self.linelen = LINELEN-1 + + def write(self, data): + self.data = self.data + data + datalen = len(self.data) + todo = (datalen/3)*3 + data = self.data[:todo] + self.data = self.data[todo:] + if not data: + return + self.hqxdata = self.hqxdata + binascii.b2a_hqx(data) + self._flush(0) + + def _flush(self, force): + first = 0 + while first <= len(self.hqxdata)-self.linelen: + last = first + self.linelen + self.ofp.write(self.hqxdata[first:last]+'\n') + self.linelen = LINELEN + first = last + self.hqxdata = self.hqxdata[first:] + if force: + self.ofp.write(self.hqxdata + ':\n') + + def close(self): + if self.data: + self.hqxdata = \ + self.hqxdata + binascii.b2a_hqx(self.data) + self._flush(1) + self.ofp.close() + del self.ofp class _Rlecoderengine: - """Write data to the RLE-coder in suitably large chunks""" - - def __init__(self, ofp): - self.ofp = ofp - self.data = '' - - def write(self, data): - self.data = self.data + data - if len(self.data) < REASONABLY_LARGE: - return - rledata = binascii.rlecode_hqx(self.data) - self.ofp.write(rledata) - self.data = '' - - def close(self): - if self.data: - rledata = binascii.rlecode_hqx(self.data) - self.ofp.write(rledata) - self.ofp.close() - del self.ofp + """Write data to the RLE-coder in suitably large chunks""" + + def __init__(self, ofp): + self.ofp = ofp + self.data = '' + + def write(self, data): + self.data = self.data + data + if len(self.data) < REASONABLY_LARGE: + return + rledata = binascii.rlecode_hqx(self.data) + self.ofp.write(rledata) + self.data = '' + + def close(self): + if self.data: + rledata = binascii.rlecode_hqx(self.data) + self.ofp.write(rledata) + self.ofp.close() + del self.ofp class BinHex: - def __init__(self, (name, finfo, dlen, rlen), ofp): - if type(ofp) == type(''): - ofname = ofp - ofp = open(ofname, 'w') - if os.name == 'mac': - fss = macfs.FSSpec(ofname) - fss.SetCreatorType('BnHq', 'TEXT') - ofp.write('(This file must be converted with BinHex 4.0)\n\n:') - hqxer = _Hqxcoderengine(ofp) - self.ofp = _Rlecoderengine(hqxer) - self.crc = 0 - if finfo == None: - finfo = FInfo() - self.dlen = dlen - self.rlen = rlen - self._writeinfo(name, finfo) - self.state = _DID_HEADER - - def _writeinfo(self, name, finfo): - name = name - nl = len(name) - if nl > 63: - raise Error, 'Filename too long' - d = chr(nl) + name + '\0' - d2 = finfo.Type + finfo.Creator - - # Force all structs to be packed with big-endian - d3 = struct.pack('>h', finfo.Flags) - d4 = struct.pack('>ii', self.dlen, self.rlen) - info = d + d2 + d3 + d4 - self._write(info) - self._writecrc() - - def _write(self, data): - self.crc = binascii.crc_hqx(data, self.crc) - self.ofp.write(data) - - def _writecrc(self): - # XXXX Should this be here?? - # self.crc = binascii.crc_hqx('\0\0', self.crc) - self.ofp.write(struct.pack('>h', self.crc)) - self.crc = 0 - - def write(self, data): - if self.state != _DID_HEADER: - raise Error, 'Writing data at the wrong time' - self.dlen = self.dlen - len(data) - self._write(data) - - def close_data(self): - if self.dlen <> 0: - raise Error, 'Incorrect data size, diff='+`self.rlen` - self._writecrc() - self.state = _DID_DATA - - def write_rsrc(self, data): - if self.state < _DID_DATA: - self.close_data() - if self.state != _DID_DATA: - raise Error, 'Writing resource data at the wrong time' - self.rlen = self.rlen - len(data) - self._write(data) - - def close(self): - if self.state < _DID_DATA: - self.close_data() - if self.state != _DID_DATA: - raise Error, 'Close at the wrong time' - if self.rlen <> 0: - raise Error, \ - "Incorrect resource-datasize, diff="+`self.rlen` - self._writecrc() - self.ofp.close() - self.state = None - del self.ofp - + def __init__(self, (name, finfo, dlen, rlen), ofp): + if type(ofp) == type(''): + ofname = ofp + ofp = open(ofname, 'w') + if os.name == 'mac': + fss = macfs.FSSpec(ofname) + fss.SetCreatorType('BnHq', 'TEXT') + ofp.write('(This file must be converted with BinHex 4.0)\n\n:') + hqxer = _Hqxcoderengine(ofp) + self.ofp = _Rlecoderengine(hqxer) + self.crc = 0 + if finfo == None: + finfo = FInfo() + self.dlen = dlen + self.rlen = rlen + self._writeinfo(name, finfo) + self.state = _DID_HEADER + + def _writeinfo(self, name, finfo): + name = name + nl = len(name) + if nl > 63: + raise Error, 'Filename too long' + d = chr(nl) + name + '\0' + d2 = finfo.Type + finfo.Creator + + # Force all structs to be packed with big-endian + d3 = struct.pack('>h', finfo.Flags) + d4 = struct.pack('>ii', self.dlen, self.rlen) + info = d + d2 + d3 + d4 + self._write(info) + self._writecrc() + + def _write(self, data): + self.crc = binascii.crc_hqx(data, self.crc) + self.ofp.write(data) + + def _writecrc(self): + # XXXX Should this be here?? + # self.crc = binascii.crc_hqx('\0\0', self.crc) + self.ofp.write(struct.pack('>h', self.crc)) + self.crc = 0 + + def write(self, data): + if self.state != _DID_HEADER: + raise Error, 'Writing data at the wrong time' + self.dlen = self.dlen - len(data) + self._write(data) + + def close_data(self): + if self.dlen <> 0: + raise Error, 'Incorrect data size, diff='+`self.rlen` + self._writecrc() + self.state = _DID_DATA + + def write_rsrc(self, data): + if self.state < _DID_DATA: + self.close_data() + if self.state != _DID_DATA: + raise Error, 'Writing resource data at the wrong time' + self.rlen = self.rlen - len(data) + self._write(data) + + def close(self): + if self.state < _DID_DATA: + self.close_data() + if self.state != _DID_DATA: + raise Error, 'Close at the wrong time' + if self.rlen <> 0: + raise Error, \ + "Incorrect resource-datasize, diff="+`self.rlen` + self._writecrc() + self.ofp.close() + self.state = None + del self.ofp + def binhex(inp, out): - """(infilename, outfilename) - Create binhex-encoded copy of a file""" - finfo = getfileinfo(inp) - ofp = BinHex(finfo, out) - - ifp = open(inp, 'rb') - # XXXX Do textfile translation on non-mac systems - while 1: - d = ifp.read(128000) - if not d: break - ofp.write(d) - ofp.close_data() - ifp.close() - - ifp = openrsrc(inp, 'rb') - while 1: - d = ifp.read(128000) - if not d: break - ofp.write_rsrc(d) - ofp.close() - ifp.close() + """(infilename, outfilename) - Create binhex-encoded copy of a file""" + finfo = getfileinfo(inp) + ofp = BinHex(finfo, out) + + ifp = open(inp, 'rb') + # XXXX Do textfile translation on non-mac systems + while 1: + d = ifp.read(128000) + if not d: break + ofp.write(d) + ofp.close_data() + ifp.close() + + ifp = openrsrc(inp, 'rb') + while 1: + d = ifp.read(128000) + if not d: break + ofp.write_rsrc(d) + ofp.close() + ifp.close() class _Hqxdecoderengine: - """Read data via the decoder in 4-byte chunks""" - - def __init__(self, ifp): - self.ifp = ifp - self.eof = 0 - - def read(self, totalwtd): - """Read at least wtd bytes (or until EOF)""" - decdata = '' - wtd = totalwtd - # - # The loop here is convoluted, since we don't really now how - # much to decode: there may be newlines in the incoming data. - while wtd > 0: - if self.eof: return decdata - wtd = ((wtd+2)/3)*4 - data = self.ifp.read(wtd) - # - # Next problem: there may not be a complete number of - # bytes in what we pass to a2b. Solve by yet another - # loop. - # - while 1: - try: - decdatacur, self.eof = \ - binascii.a2b_hqx(data) - break - except binascii.Incomplete: - pass - newdata = self.ifp.read(1) - if not newdata: - raise Error, \ - 'Premature EOF on binhex file' - data = data + newdata - decdata = decdata + decdatacur - wtd = totalwtd - len(decdata) - if not decdata and not self.eof: - raise Error, 'Premature EOF on binhex file' - return decdata - - def close(self): - self.ifp.close() + """Read data via the decoder in 4-byte chunks""" + + def __init__(self, ifp): + self.ifp = ifp + self.eof = 0 + + def read(self, totalwtd): + """Read at least wtd bytes (or until EOF)""" + decdata = '' + wtd = totalwtd + # + # The loop here is convoluted, since we don't really now how + # much to decode: there may be newlines in the incoming data. + while wtd > 0: + if self.eof: return decdata + wtd = ((wtd+2)/3)*4 + data = self.ifp.read(wtd) + # + # Next problem: there may not be a complete number of + # bytes in what we pass to a2b. Solve by yet another + # loop. + # + while 1: + try: + decdatacur, self.eof = \ + binascii.a2b_hqx(data) + break + except binascii.Incomplete: + pass + newdata = self.ifp.read(1) + if not newdata: + raise Error, \ + 'Premature EOF on binhex file' + data = data + newdata + decdata = decdata + decdatacur + wtd = totalwtd - len(decdata) + if not decdata and not self.eof: + raise Error, 'Premature EOF on binhex file' + return decdata + + def close(self): + self.ifp.close() class _Rledecoderengine: - """Read data via the RLE-coder""" - - def __init__(self, ifp): - self.ifp = ifp - self.pre_buffer = '' - self.post_buffer = '' - self.eof = 0 - - def read(self, wtd): - if wtd > len(self.post_buffer): - self._fill(wtd-len(self.post_buffer)) - rv = self.post_buffer[:wtd] - self.post_buffer = self.post_buffer[wtd:] - return rv - - def _fill(self, wtd): - self.pre_buffer = self.pre_buffer + self.ifp.read(wtd+4) - if self.ifp.eof: - self.post_buffer = self.post_buffer + \ - binascii.rledecode_hqx(self.pre_buffer) - self.pre_buffer = '' - return - - # - # Obfuscated code ahead. We have to take care that we don't - # end up with an orphaned RUNCHAR later on. So, we keep a couple - # of bytes in the buffer, depending on what the end of - # the buffer looks like: - # '\220\0\220' - Keep 3 bytes: repeated \220 (escaped as \220\0) - # '?\220' - Keep 2 bytes: repeated something-else - # '\220\0' - Escaped \220: Keep 2 bytes. - # '?\220?' - Complete repeat sequence: decode all - # otherwise: keep 1 byte. - # - mark = len(self.pre_buffer) - if self.pre_buffer[-3:] == RUNCHAR + '\0' + RUNCHAR: - mark = mark - 3 - elif self.pre_buffer[-1] == RUNCHAR: - mark = mark - 2 - elif self.pre_buffer[-2:] == RUNCHAR + '\0': - mark = mark - 2 - elif self.pre_buffer[-2] == RUNCHAR: - pass # Decode all - else: - mark = mark - 1 - - self.post_buffer = self.post_buffer + \ - binascii.rledecode_hqx(self.pre_buffer[:mark]) - self.pre_buffer = self.pre_buffer[mark:] - - def close(self): - self.ifp.close() + """Read data via the RLE-coder""" + + def __init__(self, ifp): + self.ifp = ifp + self.pre_buffer = '' + self.post_buffer = '' + self.eof = 0 + + def read(self, wtd): + if wtd > len(self.post_buffer): + self._fill(wtd-len(self.post_buffer)) + rv = self.post_buffer[:wtd] + self.post_buffer = self.post_buffer[wtd:] + return rv + + def _fill(self, wtd): + self.pre_buffer = self.pre_buffer + self.ifp.read(wtd+4) + if self.ifp.eof: + self.post_buffer = self.post_buffer + \ + binascii.rledecode_hqx(self.pre_buffer) + self.pre_buffer = '' + return + + # + # Obfuscated code ahead. We have to take care that we don't + # end up with an orphaned RUNCHAR later on. So, we keep a couple + # of bytes in the buffer, depending on what the end of + # the buffer looks like: + # '\220\0\220' - Keep 3 bytes: repeated \220 (escaped as \220\0) + # '?\220' - Keep 2 bytes: repeated something-else + # '\220\0' - Escaped \220: Keep 2 bytes. + # '?\220?' - Complete repeat sequence: decode all + # otherwise: keep 1 byte. + # + mark = len(self.pre_buffer) + if self.pre_buffer[-3:] == RUNCHAR + '\0' + RUNCHAR: + mark = mark - 3 + elif self.pre_buffer[-1] == RUNCHAR: + mark = mark - 2 + elif self.pre_buffer[-2:] == RUNCHAR + '\0': + mark = mark - 2 + elif self.pre_buffer[-2] == RUNCHAR: + pass # Decode all + else: + mark = mark - 1 + + self.post_buffer = self.post_buffer + \ + binascii.rledecode_hqx(self.pre_buffer[:mark]) + self.pre_buffer = self.pre_buffer[mark:] + + def close(self): + self.ifp.close() class HexBin: - def __init__(self, ifp): - if type(ifp) == type(''): - ifp = open(ifp) - # - # Find initial colon. - # - while 1: - ch = ifp.read(1) - if not ch: - raise Error, "No binhex data found" - # Cater for \r\n terminated lines (which show up as \n\r, hence - # all lines start with \r) - if ch == '\r': - continue - if ch == ':': - break - if ch != '\n': - dummy = ifp.readline() - - hqxifp = _Hqxdecoderengine(ifp) - self.ifp = _Rledecoderengine(hqxifp) - self.crc = 0 - self._readheader() - - def _read(self, len): - data = self.ifp.read(len) - self.crc = binascii.crc_hqx(data, self.crc) - return data - - def _checkcrc(self): - filecrc = struct.unpack('>h', self.ifp.read(2))[0] & 0xffff - #self.crc = binascii.crc_hqx('\0\0', self.crc) - # XXXX Is this needed?? - self.crc = self.crc & 0xffff - if filecrc != self.crc: - raise Error, 'CRC error, computed %x, read %x' \ - %(self.crc, filecrc) - self.crc = 0 - - def _readheader(self): - len = self._read(1) - fname = self._read(ord(len)) - rest = self._read(1+4+4+2+4+4) - self._checkcrc() - - type = rest[1:5] - creator = rest[5:9] - flags = struct.unpack('>h', rest[9:11])[0] - self.dlen = struct.unpack('>l', rest[11:15])[0] - self.rlen = struct.unpack('>l', rest[15:19])[0] - - self.FName = fname - self.FInfo = FInfo() - self.FInfo.Creator = creator - self.FInfo.Type = type - self.FInfo.Flags = flags - - self.state = _DID_HEADER - - def read(self, *n): - if self.state != _DID_HEADER: - raise Error, 'Read data at wrong time' - if n: - n = n[0] - n = min(n, self.dlen) - else: - n = self.dlen - rv = '' - while len(rv) < n: - rv = rv + self._read(n-len(rv)) - self.dlen = self.dlen - n - return rv - - def close_data(self): - if self.state != _DID_HEADER: - raise Error, 'close_data at wrong time' - if self.dlen: - dummy = self._read(self.dlen) - self._checkcrc() - self.state = _DID_DATA - - def read_rsrc(self, *n): - if self.state == _DID_HEADER: - self.close_data() - if self.state != _DID_DATA: - raise Error, 'Read resource data at wrong time' - if n: - n = n[0] - n = min(n, self.rlen) - else: - n = self.rlen - self.rlen = self.rlen - n - return self._read(n) - - def close(self): - if self.rlen: - dummy = self.read_rsrc(self.rlen) - self._checkcrc() - self.state = _DID_RSRC - self.ifp.close() - + def __init__(self, ifp): + if type(ifp) == type(''): + ifp = open(ifp) + # + # Find initial colon. + # + while 1: + ch = ifp.read(1) + if not ch: + raise Error, "No binhex data found" + # Cater for \r\n terminated lines (which show up as \n\r, hence + # all lines start with \r) + if ch == '\r': + continue + if ch == ':': + break + if ch != '\n': + dummy = ifp.readline() + + hqxifp = _Hqxdecoderengine(ifp) + self.ifp = _Rledecoderengine(hqxifp) + self.crc = 0 + self._readheader() + + def _read(self, len): + data = self.ifp.read(len) + self.crc = binascii.crc_hqx(data, self.crc) + return data + + def _checkcrc(self): + filecrc = struct.unpack('>h', self.ifp.read(2))[0] & 0xffff + #self.crc = binascii.crc_hqx('\0\0', self.crc) + # XXXX Is this needed?? + self.crc = self.crc & 0xffff + if filecrc != self.crc: + raise Error, 'CRC error, computed %x, read %x' \ + %(self.crc, filecrc) + self.crc = 0 + + def _readheader(self): + len = self._read(1) + fname = self._read(ord(len)) + rest = self._read(1+4+4+2+4+4) + self._checkcrc() + + type = rest[1:5] + creator = rest[5:9] + flags = struct.unpack('>h', rest[9:11])[0] + self.dlen = struct.unpack('>l', rest[11:15])[0] + self.rlen = struct.unpack('>l', rest[15:19])[0] + + self.FName = fname + self.FInfo = FInfo() + self.FInfo.Creator = creator + self.FInfo.Type = type + self.FInfo.Flags = flags + + self.state = _DID_HEADER + + def read(self, *n): + if self.state != _DID_HEADER: + raise Error, 'Read data at wrong time' + if n: + n = n[0] + n = min(n, self.dlen) + else: + n = self.dlen + rv = '' + while len(rv) < n: + rv = rv + self._read(n-len(rv)) + self.dlen = self.dlen - n + return rv + + def close_data(self): + if self.state != _DID_HEADER: + raise Error, 'close_data at wrong time' + if self.dlen: + dummy = self._read(self.dlen) + self._checkcrc() + self.state = _DID_DATA + + def read_rsrc(self, *n): + if self.state == _DID_HEADER: + self.close_data() + if self.state != _DID_DATA: + raise Error, 'Read resource data at wrong time' + if n: + n = n[0] + n = min(n, self.rlen) + else: + n = self.rlen + self.rlen = self.rlen - n + return self._read(n) + + def close(self): + if self.rlen: + dummy = self.read_rsrc(self.rlen) + self._checkcrc() + self.state = _DID_RSRC + self.ifp.close() + def hexbin(inp, out): - """(infilename, outfilename) - Decode binhexed file""" - ifp = HexBin(inp) - finfo = ifp.FInfo - if not out: - out = ifp.FName - if os.name == 'mac': - ofss = macfs.FSSpec(out) - out = ofss.as_pathname() - - ofp = open(out, 'wb') - # XXXX Do translation on non-mac systems - while 1: - d = ifp.read(128000) - if not d: break - ofp.write(d) - ofp.close() - ifp.close_data() - - d = ifp.read_rsrc(128000) - if d: - ofp = openrsrc(out, 'wb') - ofp.write(d) - while 1: - d = ifp.read_rsrc(128000) - if not d: break - ofp.write(d) - ofp.close() - - if os.name == 'mac': - nfinfo = ofss.GetFInfo() - nfinfo.Creator = finfo.Creator - nfinfo.Type = finfo.Type - nfinfo.Flags = finfo.Flags - ofss.SetFInfo(nfinfo) - - ifp.close() + """(infilename, outfilename) - Decode binhexed file""" + ifp = HexBin(inp) + finfo = ifp.FInfo + if not out: + out = ifp.FName + if os.name == 'mac': + ofss = macfs.FSSpec(out) + out = ofss.as_pathname() + + ofp = open(out, 'wb') + # XXXX Do translation on non-mac systems + while 1: + d = ifp.read(128000) + if not d: break + ofp.write(d) + ofp.close() + ifp.close_data() + + d = ifp.read_rsrc(128000) + if d: + ofp = openrsrc(out, 'wb') + ofp.write(d) + while 1: + d = ifp.read_rsrc(128000) + if not d: break + ofp.write(d) + ofp.close() + + if os.name == 'mac': + nfinfo = ofss.GetFInfo() + nfinfo.Creator = finfo.Creator + nfinfo.Type = finfo.Type + nfinfo.Flags = finfo.Flags + ofss.SetFInfo(nfinfo) + + ifp.close() def _test(): - if os.name == 'mac': - fss, ok = macfs.PromptGetFile('File to convert:') - if not ok: - sys.exit(0) - fname = fss.as_pathname() - else: - fname = sys.argv[1] - binhex(fname, fname+'.hqx') - hexbin(fname+'.hqx', fname+'.viahqx') - #hexbin(fname, fname+'.unpacked') - sys.exit(1) - + if os.name == 'mac': + fss, ok = macfs.PromptGetFile('File to convert:') + if not ok: + sys.exit(0) + fname = fss.as_pathname() + else: + fname = sys.argv[1] + binhex(fname, fname+'.hqx') + hexbin(fname+'.hqx', fname+'.viahqx') + #hexbin(fname, fname+'.unpacked') + sys.exit(1) + if __name__ == '__main__': - _test() + _test() diff --git a/Lib/bisect.py b/Lib/bisect.py index 5fbc4ef..47ef509 100644 --- a/Lib/bisect.py +++ b/Lib/bisect.py @@ -1,25 +1,23 @@ -# Bisection algorithms +"""Bisection algorithms.""" -# Insert item x in list a, and keep it sorted assuming a is sorted - def insort(a, x, lo=0, hi=None): - if hi is None: - hi = len(a) - while lo < hi: - mid = (lo+hi)/2 - if x < a[mid]: hi = mid - else: lo = mid+1 - a.insert(lo, x) - + """Insert item x in list a, and keep it sorted assuming a is sorted.""" + if hi is None: + hi = len(a) + while lo < hi: + mid = (lo+hi)/2 + if x < a[mid]: hi = mid + else: lo = mid+1 + a.insert(lo, x) -# Find the index where to insert item x in list a, assuming a is sorted def bisect(a, x, lo=0, hi=None): - if hi is None: - hi = len(a) - while lo < hi: - mid = (lo+hi)/2 - if x < a[mid]: hi = mid - else: lo = mid+1 - return lo + """Find the index where to insert item x in list a, assuming a is sorted.""" + if hi is None: + hi = len(a) + while lo < hi: + mid = (lo+hi)/2 + if x < a[mid]: hi = mid + else: lo = mid+1 + return lo diff --git a/Lib/calendar.py b/Lib/calendar.py index c9bc497..fa96278 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -1,6 +1,4 @@ -############################### -# Calendar printing functions # -############################### +"""Calendar printing functions""" # Revision 2: uses funtions from built-in time module @@ -22,149 +20,149 @@ February = 2 mdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] # Full and abbreviated names of weekdays -day_name = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', \ - 'Friday', 'Saturday', 'Sunday'] +day_name = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', + 'Friday', 'Saturday', 'Sunday'] day_abbr = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] # Full and abbreviated names of months (1-based arrays!!!) -month_name = ['', 'January', 'February', 'March', 'April', \ - 'May', 'June', 'July', 'August', \ - 'September', 'October', 'November', 'December'] -month_abbr = [' ', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', \ - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] +month_name = ['', 'January', 'February', 'March', 'April', + 'May', 'June', 'July', 'August', + 'September', 'October', 'November', 'December'] +month_abbr = [' ', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] -# Return 1 for leap years, 0 for non-leap years def isleap(year): - return year % 4 == 0 and (year % 100 <> 0 or year % 400 == 0) + """Return 1 for leap years, 0 for non-leap years.""" + return year % 4 == 0 and (year % 100 <> 0 or year % 400 == 0) -# Return number of leap years in range [y1, y2) -# Assume y1 <= y2 and no funny (non-leap century) years def leapdays(y1, y2): - return (y2+3)/4 - (y1+3)/4 + """Return number of leap years in range [y1, y2). + Assume y1 <= y2 and no funny (non-leap century) years.""" + return (y2+3)/4 - (y1+3)/4 -# Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12), day (1-31) def weekday(year, month, day): - secs = mktime((year, month, day, 0, 0, 0, 0, 0, 0)) - tuple = localtime(secs) - return tuple[6] + """Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12), day (1-31).""" + secs = mktime((year, month, day, 0, 0, 0, 0, 0, 0)) + tuple = localtime(secs) + return tuple[6] -# Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for year, month def monthrange(year, month): - if not 1 <= month <= 12: raise ValueError, 'bad month number' - day1 = weekday(year, month, 1) - ndays = mdays[month] + (month == February and isleap(year)) - return day1, ndays + """Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for year, month.""" + if not 1 <= month <= 12: raise ValueError, 'bad month number' + day1 = weekday(year, month, 1) + ndays = mdays[month] + (month == February and isleap(year)) + return day1, ndays -# Return a matrix representing a month's calendar -# Each row represents a week; days outside this month are zero def _monthcalendar(year, month): - day1, ndays = monthrange(year, month) - rows = [] - r7 = range(7) - day = 1 - day1 - while day <= ndays: - row = [0, 0, 0, 0, 0, 0, 0] - for i in r7: - if 1 <= day <= ndays: row[i] = day - day = day + 1 - rows.append(row) - return rows - -# Caching interface to _monthcalendar + """Return a matrix representing a month's calendar. + Each row represents a week; days outside this month are zero.""" + day1, ndays = monthrange(year, month) + rows = [] + r7 = range(7) + day = 1 - day1 + while day <= ndays: + row = [0, 0, 0, 0, 0, 0, 0] + for i in r7: + if 1 <= day <= ndays: row[i] = day + day = day + 1 + rows.append(row) + return rows + _mc_cache = {} def monthcalendar(year, month): - key = (year, month) - if _mc_cache.has_key(key): - return _mc_cache[key] - else: - _mc_cache[key] = ret = _monthcalendar(year, month) - return ret - -# Center a string in a field + """Caching interface to _monthcalendar.""" + key = (year, month) + if _mc_cache.has_key(key): + return _mc_cache[key] + else: + _mc_cache[key] = ret = _monthcalendar(year, month) + return ret + def _center(str, width): - n = width - len(str) - if n <= 0: return str - return ' '*((n+1)/2) + str + ' '*((n)/2) + """Center a string in a field.""" + n = width - len(str) + if n <= 0: return str + return ' '*((n+1)/2) + str + ' '*((n)/2) # XXX The following code knows that print separates items with space! -# Print a single week (no newline) def prweek(week, width): - for day in week: - if day == 0: s = '' - else: s = `day` - print _center(s, width), + """Print a single week (no newline).""" + for day in week: + if day == 0: s = '' + else: s = `day` + print _center(s, width), -# Return a header for a week def weekheader(width): - str = '' - if width >= 9: names = day_name - else: names = day_abbr - for i in range(7): - if str: str = str + ' ' - str = str + _center(names[i%7][:width], width) - return str - -# Print a month's calendar + """Return a header for a week.""" + str = '' + if width >= 9: names = day_name + else: names = day_abbr + for i in range(7): + if str: str = str + ' ' + str = str + _center(names[i%7][:width], width) + return str + def prmonth(year, month, w = 0, l = 0): - w = max(2, w) - l = max(1, l) - print _center(month_name[month] + ' ' + `year`, 7*(w+1) - 1), - print '\n'*l, - print weekheader(w), - print '\n'*l, - for week in monthcalendar(year, month): - prweek(week, w) - print '\n'*l, + """Print a month's calendar.""" + w = max(2, w) + l = max(1, l) + print _center(month_name[month] + ' ' + `year`, 7*(w+1) - 1), + print '\n'*l, + print weekheader(w), + print '\n'*l, + for week in monthcalendar(year, month): + prweek(week, w) + print '\n'*l, # Spacing of month columns -_colwidth = 7*3 - 1 # Amount printed by prweek() -_spacing = ' '*4 # Spaces between columns +_colwidth = 7*3 - 1 # Amount printed by prweek() +_spacing = ' '*4 # Spaces between columns -# 3-column formatting for year calendars def format3c(a, b, c): - print _center(a, _colwidth), - print _spacing, - print _center(b, _colwidth), - print _spacing, - print _center(c, _colwidth) + """3-column formatting for year calendars""" + print _center(a, _colwidth), + print _spacing, + print _center(b, _colwidth), + print _spacing, + print _center(c, _colwidth) -# Print a year's calendar def prcal(year): - header = weekheader(2) - format3c('', `year`, '') - for q in range(January, January+12, 3): - print - format3c(month_name[q], month_name[q+1], month_name[q+2]) - format3c(header, header, header) - data = [] - height = 0 - for month in range(q, q+3): - cal = monthcalendar(year, month) - if len(cal) > height: height = len(cal) - data.append(cal) - for i in range(height): - for cal in data: - if i >= len(cal): - print ' '*_colwidth, - else: - prweek(cal[i], 2) - print _spacing, - print - -# Unrelated but handy function to calculate Unix timestamp from GMT + """Print a year's calendar.""" + header = weekheader(2) + format3c('', `year`, '') + for q in range(January, January+12, 3): + print + format3c(month_name[q], month_name[q+1], month_name[q+2]) + format3c(header, header, header) + data = [] + height = 0 + for month in range(q, q+3): + cal = monthcalendar(year, month) + if len(cal) > height: height = len(cal) + data.append(cal) + for i in range(height): + for cal in data: + if i >= len(cal): + print ' '*_colwidth, + else: + prweek(cal[i], 2) + print _spacing, + print + EPOCH = 1970 def timegm(tuple): - year, month, day, hour, minute, second = tuple[:6] - assert year >= EPOCH - assert 1 <= month <= 12 - days = 365*(year-EPOCH) + leapdays(EPOCH, year) - for i in range(1, month): - days = days + mdays[i] - if month > 2 and isleap(year): - days = days + 1 - days = days + day - 1 - hours = days*24 + hour - minutes = hours*60 + minute - seconds = minutes*60 + second - return seconds + """Unrelated but handy function to calculate Unix timestamp from GMT.""" + year, month, day, hour, minute, second = tuple[:6] + assert year >= EPOCH + assert 1 <= month <= 12 + days = 365*(year-EPOCH) + leapdays(EPOCH, year) + for i in range(1, month): + days = days + mdays[i] + if month > 2 and isleap(year): + days = days + 1 + days = days + day - 1 + hours = days*24 + hour + minutes = hours*60 + minute + seconds = minutes*60 + second + return seconds @@ -1,39 +1,39 @@ -# A generic class to build line-oriented command interpreters -# -# Interpreters constructed with this class obey the following conventions: -# -# 1. End of file on input is processed as the command 'EOF'. -# 2. A command is parsed out of each line by collecting the prefix composed -# of characters in the identchars member. -# 3. A command `foo' is dispatched to a method 'do_foo()'; the do_ method -# is passed a single argument consisting of the remainder of the line. -# 4. Typing an empty line repeats the last command. (Actually, it calls the -# method `emptyline', which may be overridden in a subclass.) -# 5. There is a predefined `help' method. Given an argument `topic', it -# calls the command `help_topic'. With no arguments, it lists all topics -# with defined help_ functions, broken into up to three topics; documented -# commands, miscellaneous help topics, and undocumented commands. -# 6. The command '?' is a synonym for `help'. The command '!' is a synonym -# for `shell', if a do_shell method exists. -# -# The `default' method may be overridden to intercept commands for which there -# is no do_ method. -# -# The data member `self.ruler' sets the character used to draw separator lines -# in the help messages. If empty, no ruler line is drawn. It defaults to "=". -# -# If the value of `self.intro' is nonempty when the cmdloop method is called, -# it is printed out on interpreter startup. This value may be overridden -# via an optional argument to the cmdloop() method. -# -# The data members `self.doc_header', `self.misc_header', and -# `self.undoc_header' set the headers used for the help function's -# listings of documented functions, miscellaneous topics, and undocumented -# functions respectively. -# -# These interpreters use raw_input; thus, if the readline module is loaded, -# they automatically support Emacs-like command history and editing features. -# +"""A generic class to build line-oriented command interpreters. + +Interpreters constructed with this class obey the following conventions: + +1. End of file on input is processed as the command 'EOF'. +2. A command is parsed out of each line by collecting the prefix composed + of characters in the identchars member. +3. A command `foo' is dispatched to a method 'do_foo()'; the do_ method + is passed a single argument consisting of the remainder of the line. +4. Typing an empty line repeats the last command. (Actually, it calls the + method `emptyline', which may be overridden in a subclass.) +5. There is a predefined `help' method. Given an argument `topic', it + calls the command `help_topic'. With no arguments, it lists all topics + with defined help_ functions, broken into up to three topics; documented + commands, miscellaneous help topics, and undocumented commands. +6. The command '?' is a synonym for `help'. The command '!' is a synonym + for `shell', if a do_shell method exists. + +The `default' method may be overridden to intercept commands for which there +is no do_ method. + +The data member `self.ruler' sets the character used to draw separator lines +in the help messages. If empty, no ruler line is drawn. It defaults to "=". + +If the value of `self.intro' is nonempty when the cmdloop method is called, +it is printed out on interpreter startup. This value may be overridden +via an optional argument to the cmdloop() method. + +The data members `self.doc_header', `self.misc_header', and +`self.undoc_header' set the headers used for the help function's +listings of documented functions, miscellaneous topics, and undocumented +functions respectively. + +These interpreters use raw_input; thus, if the readline module is loaded, +they automatically support Emacs-like command history and editing features. +""" import string @@ -41,147 +41,147 @@ PROMPT = '(Cmd) ' IDENTCHARS = string.letters + string.digits + '_' class Cmd: - prompt = PROMPT - identchars = IDENTCHARS - ruler = '=' - lastcmd = '' - cmdqueue = [] - intro = None - doc_leader = "" - doc_header = "Documented commands (type help <topic>):" - misc_header = "Miscellaneous help topics:" - undoc_header = "Undocumented commands:" - nohelp = "*** No help on %s" - - def __init__(self): pass - - def cmdloop(self, intro=None): - self.preloop() - if intro != None: - self.intro = intro - if self.intro: - print self.intro - stop = None - while not stop: - if self.cmdqueue: - line = self.cmdqueue[0] - del self.cmdqueue[0] - else: - try: - line = raw_input(self.prompt) - except EOFError: - line = 'EOF' - line = self.precmd(line) - stop = self.onecmd(line) - stop = self.postcmd(stop, line) - self.postloop() - - def precmd(self, line): - return line - - def postcmd(self, stop, line): - return stop - - def preloop(self): - pass - - def postloop(self): - pass - - def onecmd(self, line): - line = string.strip(line) - if line == '?': - line = 'help' - elif line == '!': - if hasattr(self, 'do_shell'): - line = 'shell' - else: - return self.default(line) - elif not line: - return self.emptyline() - self.lastcmd = line - i, n = 0, len(line) - while i < n and line[i] in self.identchars: i = i+1 - cmd, arg = line[:i], string.strip(line[i:]) - if cmd == '': - return self.default(line) - else: - try: - func = getattr(self, 'do_' + cmd) - except AttributeError: - return self.default(line) - return func(arg) - - def emptyline(self): - if self.lastcmd: - return self.onecmd(self.lastcmd) - - def default(self, line): - print '*** Unknown syntax:', line - - def do_help(self, arg): - if arg: - # XXX check arg syntax - try: - func = getattr(self, 'help_' + arg) - except: - try: - doc=getattr(self, 'do_' + arg).__doc__ - if doc: - print doc - return - except: - pass - print self.nohelp % (arg,) - return - func() - else: - # Inheritance says we have to look in class and - # base classes; order is not important. - names = [] - classes = [self.__class__] - while classes: - aclass = classes[0] - if aclass.__bases__: - classes = classes + list(aclass.__bases__) - names = names + dir(aclass) - del classes[0] - cmds_doc = [] - cmds_undoc = [] - help = {} - for name in names: - if name[:5] == 'help_': - help[name[5:]]=1 - names.sort() - # There can be duplicates if routines overridden - prevname = '' - for name in names: - if name[:3] == 'do_': - if name == prevname: - continue - prevname = name - cmd=name[3:] - if help.has_key(cmd): - cmds_doc.append(cmd) - del help[cmd] - elif getattr(self, name).__doc__: - cmds_doc.append(cmd) - else: - cmds_undoc.append(cmd) - print self.doc_leader - self.print_topics(self.doc_header, cmds_doc, 15,80) - self.print_topics(self.misc_header, help.keys(),15,80) - self.print_topics(self.undoc_header, cmds_undoc, 15,80) - - def print_topics(self, header, cmds, cmdlen, maxcol): - if cmds: - print header; - if self.ruler: - print self.ruler * len(header) - (cmds_per_line,junk)=divmod(maxcol,cmdlen) - col=cmds_per_line - for cmd in cmds: - if col==0: print - print (("%-"+`cmdlen`+"s") % cmd), - col = (col+1) % cmds_per_line - print "\n" + prompt = PROMPT + identchars = IDENTCHARS + ruler = '=' + lastcmd = '' + cmdqueue = [] + intro = None + doc_leader = "" + doc_header = "Documented commands (type help <topic>):" + misc_header = "Miscellaneous help topics:" + undoc_header = "Undocumented commands:" + nohelp = "*** No help on %s" + + def __init__(self): pass + + def cmdloop(self, intro=None): + self.preloop() + if intro != None: + self.intro = intro + if self.intro: + print self.intro + stop = None + while not stop: + if self.cmdqueue: + line = self.cmdqueue[0] + del self.cmdqueue[0] + else: + try: + line = raw_input(self.prompt) + except EOFError: + line = 'EOF' + line = self.precmd(line) + stop = self.onecmd(line) + stop = self.postcmd(stop, line) + self.postloop() + + def precmd(self, line): + return line + + def postcmd(self, stop, line): + return stop + + def preloop(self): + pass + + def postloop(self): + pass + + def onecmd(self, line): + line = string.strip(line) + if line == '?': + line = 'help' + elif line == '!': + if hasattr(self, 'do_shell'): + line = 'shell' + else: + return self.default(line) + elif not line: + return self.emptyline() + self.lastcmd = line + i, n = 0, len(line) + while i < n and line[i] in self.identchars: i = i+1 + cmd, arg = line[:i], string.strip(line[i:]) + if cmd == '': + return self.default(line) + else: + try: + func = getattr(self, 'do_' + cmd) + except AttributeError: + return self.default(line) + return func(arg) + + def emptyline(self): + if self.lastcmd: + return self.onecmd(self.lastcmd) + + def default(self, line): + print '*** Unknown syntax:', line + + def do_help(self, arg): + if arg: + # XXX check arg syntax + try: + func = getattr(self, 'help_' + arg) + except: + try: + doc=getattr(self, 'do_' + arg).__doc__ + if doc: + print doc + return + except: + pass + print self.nohelp % (arg,) + return + func() + else: + # Inheritance says we have to look in class and + # base classes; order is not important. + names = [] + classes = [self.__class__] + while classes: + aclass = classes[0] + if aclass.__bases__: + classes = classes + list(aclass.__bases__) + names = names + dir(aclass) + del classes[0] + cmds_doc = [] + cmds_undoc = [] + help = {} + for name in names: + if name[:5] == 'help_': + help[name[5:]]=1 + names.sort() + # There can be duplicates if routines overridden + prevname = '' + for name in names: + if name[:3] == 'do_': + if name == prevname: + continue + prevname = name + cmd=name[3:] + if help.has_key(cmd): + cmds_doc.append(cmd) + del help[cmd] + elif getattr(self, name).__doc__: + cmds_doc.append(cmd) + else: + cmds_undoc.append(cmd) + print self.doc_leader + self.print_topics(self.doc_header, cmds_doc, 15,80) + self.print_topics(self.misc_header, help.keys(),15,80) + self.print_topics(self.undoc_header, cmds_undoc, 15,80) + + def print_topics(self, header, cmds, cmdlen, maxcol): + if cmds: + print header; + if self.ruler: + print self.ruler * len(header) + (cmds_per_line,junk)=divmod(maxcol,cmdlen) + col=cmds_per_line + for cmd in cmds: + if col==0: print + print (("%-"+`cmdlen`+"s") % cmd), + col = (col+1) % cmds_per_line + print "\n" @@ -1,61 +1,63 @@ -# Module 'cmp' +"""Efficiently compare files, boolean outcome only (equal / not equal). -# Efficiently compare files, boolean outcome only (equal / not equal). - -# Tricks (used in this order): -# - Files with identical type, size & mtime are assumed to be clones -# - Files with different type or size cannot be identical -# - We keep a cache of outcomes of earlier comparisons -# - We don't fork a process to run 'cmp' but read the files ourselves +Tricks (used in this order): + - Files with identical type, size & mtime are assumed to be clones + - Files with different type or size cannot be identical + - We keep a cache of outcomes of earlier comparisons + - We don't fork a process to run 'cmp' but read the files ourselves +""" import os cache = {} -def cmp(f1, f2, shallow=1): # Compare two files, use the cache if possible. - # Return 1 for identical files, 0 for different. - # Raise exceptions if either file could not be statted, read, etc. - s1, s2 = sig(os.stat(f1)), sig(os.stat(f2)) - if s1[0] <> 8 or s2[0] <> 8: - # Either is a not a plain file -- always report as different - return 0 - if shallow and s1 == s2: - # type, size & mtime match -- report same - return 1 - if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother - # types or sizes differ -- report different - return 0 - # same type and size -- look in the cache - key = (f1, f2) - try: - cs1, cs2, outcome = cache[key] - # cache hit - if s1 == cs1 and s2 == cs2: - # cached signatures match - return outcome - # stale cached signature(s) - except KeyError: - # cache miss - pass - # really compare - outcome = do_cmp(f1, f2) - cache[key] = s1, s2, outcome - return outcome +def cmp(f1, f2, shallow=1): + """Compare two files, use the cache if possible. + Return 1 for identical files, 0 for different. + Raise exceptions if either file could not be statted, read, etc.""" + s1, s2 = sig(os.stat(f1)), sig(os.stat(f2)) + if s1[0] <> 8 or s2[0] <> 8: + # Either is a not a plain file -- always report as different + return 0 + if shallow and s1 == s2: + # type, size & mtime match -- report same + return 1 + if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother + # types or sizes differ -- report different + return 0 + # same type and size -- look in the cache + key = (f1, f2) + try: + cs1, cs2, outcome = cache[key] + # cache hit + if s1 == cs1 and s2 == cs2: + # cached signatures match + return outcome + # stale cached signature(s) + except KeyError: + # cache miss + pass + # really compare + outcome = do_cmp(f1, f2) + cache[key] = s1, s2, outcome + return outcome -def sig(st): # Return signature (i.e., type, size, mtime) from raw stat data - # 0-5: st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid - # 6-9: st_size, st_atime, st_mtime, st_ctime - type = st[0] / 4096 - size = st[6] - mtime = st[8] - return type, size, mtime +def sig(st): + """Return signature (i.e., type, size, mtime) from raw stat data + 0-5: st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid + 6-9: st_size, st_atime, st_mtime, st_ctime""" + type = st[0] / 4096 + size = st[6] + mtime = st[8] + return type, size, mtime -def do_cmp(f1, f2): # Compare two files, really - bufsize = 8*1024 # Could be tuned - fp1 = open(f1, 'rb') - fp2 = open(f2, 'rb') - while 1: - b1 = fp1.read(bufsize) - b2 = fp2.read(bufsize) - if b1 <> b2: return 0 - if not b1: return 1 +def do_cmp(f1, f2): + """Compare two files, really.""" + bufsize = 8*1024 # Could be tuned + fp1 = open(f1, 'rb') + fp2 = open(f2, 'rb') + while 1: + b1 = fp1.read(bufsize) + b2 = fp2.read(bufsize) + if b1 <> b2: return 0 + if not b1: return 1 diff --git a/Lib/cmpcache.py b/Lib/cmpcache.py index 5446e66..93332b7 100644 --- a/Lib/cmpcache.py +++ b/Lib/cmpcache.py @@ -1,13 +1,12 @@ -# Module 'cmpcache' -# -# Efficiently compare files, boolean outcome only (equal / not equal). -# -# Tricks (used in this order): -# - Use the statcache module to avoid statting files more than once -# - Files with identical type, size & mtime are assumed to be clones -# - Files with different type or size cannot be identical -# - We keep a cache of outcomes of earlier comparisons -# - We don't fork a process to run 'cmp' but read the files ourselves +"""Efficiently compare files, boolean outcome only (equal / not equal). + +Tricks (used in this order): + - Use the statcache module to avoid statting files more than once + - Files with identical type, size & mtime are assumed to be clones + - Files with different type or size cannot be identical + - We keep a cache of outcomes of earlier comparisons + - We don't fork a process to run 'cmp' but read the files ourselves +""" import os from stat import * @@ -19,50 +18,47 @@ import statcache cache = {} -# Compare two files, use the cache if possible. -# May raise os.error if a stat or open of either fails. -# def cmp(f1, f2, shallow=1): - # Return 1 for identical files, 0 for different. - # Raise exceptions if either file could not be statted, read, etc. - s1, s2 = sig(statcache.stat(f1)), sig(statcache.stat(f2)) - if not S_ISREG(s1[0]) or not S_ISREG(s2[0]): - # Either is a not a plain file -- always report as different - return 0 - if shallow and s1 == s2: - # type, size & mtime match -- report same - return 1 - if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother - # types or sizes differ -- report different - return 0 - # same type and size -- look in the cache - key = f1 + ' ' + f2 - if cache.has_key(key): - cs1, cs2, outcome = cache[key] - # cache hit - if s1 == cs1 and s2 == cs2: - # cached signatures match - return outcome - # stale cached signature(s) - # really compare - outcome = do_cmp(f1, f2) - cache[key] = s1, s2, outcome - return outcome + """Compare two files, use the cache if possible. + May raise os.error if a stat or open of either fails. + Return 1 for identical files, 0 for different. + Raise exceptions if either file could not be statted, read, etc.""" + s1, s2 = sig(statcache.stat(f1)), sig(statcache.stat(f2)) + if not S_ISREG(s1[0]) or not S_ISREG(s2[0]): + # Either is a not a plain file -- always report as different + return 0 + if shallow and s1 == s2: + # type, size & mtime match -- report same + return 1 + if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother + # types or sizes differ -- report different + return 0 + # same type and size -- look in the cache + key = f1 + ' ' + f2 + if cache.has_key(key): + cs1, cs2, outcome = cache[key] + # cache hit + if s1 == cs1 and s2 == cs2: + # cached signatures match + return outcome + # stale cached signature(s) + # really compare + outcome = do_cmp(f1, f2) + cache[key] = s1, s2, outcome + return outcome -# Return signature (i.e., type, size, mtime) from raw stat data. -# def sig(st): - return S_IFMT(st[ST_MODE]), st[ST_SIZE], st[ST_MTIME] + """Return signature (i.e., type, size, mtime) from raw stat data.""" + return S_IFMT(st[ST_MODE]), st[ST_SIZE], st[ST_MTIME] -# Compare two files, really. -# def do_cmp(f1, f2): - #print ' cmp', f1, f2 # XXX remove when debugged - bufsize = 8*1024 # Could be tuned - fp1 = open(f1, 'rb') - fp2 = open(f2, 'rb') - while 1: - b1 = fp1.read(bufsize) - b2 = fp2.read(bufsize) - if b1 <> b2: return 0 - if not b1: return 1 + """Compare two files, really.""" + #print ' cmp', f1, f2 # XXX remove when debugged + bufsize = 8*1024 # Could be tuned + fp1 = open(f1, 'rb') + fp2 = open(f2, 'rb') + while 1: + b1 = fp1.read(bufsize) + b2 = fp2.read(bufsize) + if b1 <> b2: return 0 + if not b1: return 1 diff --git a/Lib/copy_reg.py b/Lib/copy_reg.py index db4eb66..d0953bf 100644 --- a/Lib/copy_reg.py +++ b/Lib/copy_reg.py @@ -1,4 +1,4 @@ -# Helper to provide extensibility for pickle/cPickle. +"""Helper to provide extensibility for pickle/cPickle.""" dispatch_table = {} safe_constructors = {} diff --git a/Lib/dircache.py b/Lib/dircache.py index ef68b42..b0a3665 100644 --- a/Lib/dircache.py +++ b/Lib/dircache.py @@ -1,35 +1,35 @@ -# Module 'dircache' -# -# Return a sorted list of the files in a directory, using a cache -# to avoid reading the directory more often than necessary. -# Also contains a subroutine to append slashes to directories. +"""Return a sorted list of the files in a directory, using a cache +to avoid reading the directory more often than necessary. +Also contains a subroutine to append slashes to directories.""" import os cache = {} -def listdir(path): # List directory contents, using cache - try: - cached_mtime, list = cache[path] - del cache[path] - except KeyError: - cached_mtime, list = -1, [] - try: - mtime = os.stat(path)[8] - except os.error: - return [] - if mtime <> cached_mtime: - try: - list = os.listdir(path) - except os.error: - return [] - list.sort() - cache[path] = mtime, list - return list +def listdir(path): + """List directory contents, using cache.""" + try: + cached_mtime, list = cache[path] + del cache[path] + except KeyError: + cached_mtime, list = -1, [] + try: + mtime = os.stat(path)[8] + except os.error: + return [] + if mtime <> cached_mtime: + try: + list = os.listdir(path) + except os.error: + return [] + list.sort() + cache[path] = mtime, list + return list opendir = listdir # XXX backward compatibility -def annotate(head, list): # Add '/' suffixes to directories - for i in range(len(list)): - if os.path.isdir(os.path.join(head, list[i])): - list[i] = list[i] + '/' +def annotate(head, list): + """Add '/' suffixes to directories.""" + for i in range(len(list)): + if os.path.isdir(os.path.join(head, list[i])): + list[i] = list[i] + '/' diff --git a/Lib/dircmp.py b/Lib/dircmp.py index 1227aa7..13a8a04 100644 --- a/Lib/dircmp.py +++ b/Lib/dircmp.py @@ -1,6 +1,4 @@ -# Module 'dirmp' -# -# Defines a class to build directory diff tools on. +"""A class to build directory diff tools on.""" import os @@ -9,195 +7,195 @@ import cmpcache import statcache from stat import * -# Directory comparison class. -# class dircmp: - # - def new(self, a, b): # Initialize - self.a = a - self.b = b - # Properties that caller may change before calling self.run(): - self.hide = [os.curdir, os.pardir] # Names never to be shown - self.ignore = ['RCS', 'tags'] # Names ignored in comparison - # - return self - # - def run(self): # Compare everything except common subdirectories - self.a_list = filter(dircache.listdir(self.a), self.hide) - self.b_list = filter(dircache.listdir(self.b), self.hide) - self.a_list.sort() - self.b_list.sort() - self.phase1() - self.phase2() - self.phase3() - # - def phase1(self): # Compute common names - self.a_only = [] - self.common = [] - for x in self.a_list: - if x in self.b_list: - self.common.append(x) - else: - self.a_only.append(x) - # - self.b_only = [] - for x in self.b_list: - if x not in self.common: - self.b_only.append(x) - # - def phase2(self): # Distinguish files, directories, funnies - self.common_dirs = [] - self.common_files = [] - self.common_funny = [] - # - for x in self.common: - a_path = os.path.join(self.a, x) - b_path = os.path.join(self.b, x) - # - ok = 1 - try: - a_stat = statcache.stat(a_path) - except os.error, why: - # print 'Can\'t stat', a_path, ':', why[1] - ok = 0 - try: - b_stat = statcache.stat(b_path) - except os.error, why: - # print 'Can\'t stat', b_path, ':', why[1] - ok = 0 - # - if ok: - a_type = S_IFMT(a_stat[ST_MODE]) - b_type = S_IFMT(b_stat[ST_MODE]) - if a_type <> b_type: - self.common_funny.append(x) - elif S_ISDIR(a_type): - self.common_dirs.append(x) - elif S_ISREG(a_type): - self.common_files.append(x) - else: - self.common_funny.append(x) - else: - self.common_funny.append(x) - # - def phase3(self): # Find out differences between common files - xx = cmpfiles(self.a, self.b, self.common_files) - self.same_files, self.diff_files, self.funny_files = xx - # - def phase4(self): # Find out differences between common subdirectories - # A new dircmp object is created for each common subdirectory, - # these are stored in a dictionary indexed by filename. - # The hide and ignore properties are inherited from the parent - self.subdirs = {} - for x in self.common_dirs: - a_x = os.path.join(self.a, x) - b_x = os.path.join(self.b, x) - self.subdirs[x] = newdd = dircmp().new(a_x, b_x) - newdd.hide = self.hide - newdd.ignore = self.ignore - newdd.run() - # - def phase4_closure(self): # Recursively call phase4() on subdirectories - self.phase4() - for x in self.subdirs.keys(): - self.subdirs[x].phase4_closure() - # - def report(self): # Print a report on the differences between a and b - # Assume that phases 1 to 3 have been executed - # Output format is purposely lousy - print 'diff', self.a, self.b - if self.a_only: - print 'Only in', self.a, ':', self.a_only - if self.b_only: - print 'Only in', self.b, ':', self.b_only - if self.same_files: - print 'Identical files :', self.same_files - if self.diff_files: - print 'Differing files :', self.diff_files - if self.funny_files: - print 'Trouble with common files :', self.funny_files - if self.common_dirs: - print 'Common subdirectories :', self.common_dirs - if self.common_funny: - print 'Common funny cases :', self.common_funny - # - def report_closure(self): # Print reports on self and on subdirs - # If phase 4 hasn't been done, no subdir reports are printed - self.report() - try: - x = self.subdirs - except AttributeError: - return # No subdirectories computed - for x in self.subdirs.keys(): - print - self.subdirs[x].report_closure() - # - def report_phase4_closure(self): # Report and do phase 4 recursively - self.report() - self.phase4() - for x in self.subdirs.keys(): - print - self.subdirs[x].report_phase4_closure() - - -# Compare common files in two directories. -# Return: -# - files that compare equal -# - files that compare different -# - funny cases (can't stat etc.) -# + """Directory comparison class.""" + + def new(self, a, b): + """Initialize.""" + self.a = a + self.b = b + # Properties that caller may change before calling self.run(): + self.hide = [os.curdir, os.pardir] # Names never to be shown + self.ignore = ['RCS', 'tags'] # Names ignored in comparison + + return self + + def run(self): + """Compare everything except common subdirectories.""" + self.a_list = filter(dircache.listdir(self.a), self.hide) + self.b_list = filter(dircache.listdir(self.b), self.hide) + self.a_list.sort() + self.b_list.sort() + self.phase1() + self.phase2() + self.phase3() + + def phase1(self): + """Compute common names.""" + self.a_only = [] + self.common = [] + for x in self.a_list: + if x in self.b_list: + self.common.append(x) + else: + self.a_only.append(x) + + self.b_only = [] + for x in self.b_list: + if x not in self.common: + self.b_only.append(x) + + def phase2(self): + """Distinguish files, directories, funnies.""" + self.common_dirs = [] + self.common_files = [] + self.common_funny = [] + + for x in self.common: + a_path = os.path.join(self.a, x) + b_path = os.path.join(self.b, x) + + ok = 1 + try: + a_stat = statcache.stat(a_path) + except os.error, why: + # print 'Can\'t stat', a_path, ':', why[1] + ok = 0 + try: + b_stat = statcache.stat(b_path) + except os.error, why: + # print 'Can\'t stat', b_path, ':', why[1] + ok = 0 + + if ok: + a_type = S_IFMT(a_stat[ST_MODE]) + b_type = S_IFMT(b_stat[ST_MODE]) + if a_type <> b_type: + self.common_funny.append(x) + elif S_ISDIR(a_type): + self.common_dirs.append(x) + elif S_ISREG(a_type): + self.common_files.append(x) + else: + self.common_funny.append(x) + else: + self.common_funny.append(x) + + def phase3(self): + """Find out differences between common files.""" + xx = cmpfiles(self.a, self.b, self.common_files) + self.same_files, self.diff_files, self.funny_files = xx + + def phase4(self): + """Find out differences between common subdirectories. + A new dircmp object is created for each common subdirectory, + these are stored in a dictionary indexed by filename. + The hide and ignore properties are inherited from the parent.""" + self.subdirs = {} + for x in self.common_dirs: + a_x = os.path.join(self.a, x) + b_x = os.path.join(self.b, x) + self.subdirs[x] = newdd = dircmp().new(a_x, b_x) + newdd.hide = self.hide + newdd.ignore = self.ignore + newdd.run() + + def phase4_closure(self): + """Recursively call phase4() on subdirectories.""" + self.phase4() + for x in self.subdirs.keys(): + self.subdirs[x].phase4_closure() + + def report(self): + """Print a report on the differences between a and b.""" + # Assume that phases 1 to 3 have been executed + # Output format is purposely lousy + print 'diff', self.a, self.b + if self.a_only: + print 'Only in', self.a, ':', self.a_only + if self.b_only: + print 'Only in', self.b, ':', self.b_only + if self.same_files: + print 'Identical files :', self.same_files + if self.diff_files: + print 'Differing files :', self.diff_files + if self.funny_files: + print 'Trouble with common files :', self.funny_files + if self.common_dirs: + print 'Common subdirectories :', self.common_dirs + if self.common_funny: + print 'Common funny cases :', self.common_funny + + def report_closure(self): + """Print reports on self and on subdirs. + If phase 4 hasn't been done, no subdir reports are printed.""" + self.report() + try: + x = self.subdirs + except AttributeError: + return # No subdirectories computed + for x in self.subdirs.keys(): + print + self.subdirs[x].report_closure() + + def report_phase4_closure(self): + """Report and do phase 4 recursively.""" + self.report() + self.phase4() + for x in self.subdirs.keys(): + print + self.subdirs[x].report_phase4_closure() + + def cmpfiles(a, b, common): - res = ([], [], []) - for x in common: - res[cmp(os.path.join(a, x), os.path.join(b, x))].append(x) - return res - - -# Compare two files. -# Return: -# 0 for equal -# 1 for different -# 2 for funny cases (can't stat, etc.) -# -def cmp(a, b): - try: - if cmpcache.cmp(a, b): return 0 - return 1 - except os.error: - return 2 + """Compare common files in two directories. + Return: + - files that compare equal + - files that compare different + - funny cases (can't stat etc.)""" + res = ([], [], []) + for x in common: + res[cmp(os.path.join(a, x), os.path.join(b, x))].append(x) + return res -# Remove a list item. -# NB: This modifies the list argument. -# -def remove(list, item): - for i in range(len(list)): - if list[i] == item: - del list[i] - break + +def cmp(a, b): + """Compare two files. + Return: + 0 for equal + 1 for different + 2 for funny cases (can't stat, etc.)""" + + try: + if cmpcache.cmp(a, b): return 0 + return 1 + except os.error: + return 2 -# Return a copy with items that occur in skip removed. -# def filter(list, skip): - result = [] - for item in list: - if item not in skip: result.append(item) - return result + """Return a copy with items that occur in skip removed.""" + + result = [] + for item in list: + if item not in skip: result.append(item) + return result -# Demonstration and testing. -# def demo(): - import sys - import getopt - options, args = getopt.getopt(sys.argv[1:], 'r') - if len(args) <> 2: raise getopt.error, 'need exactly two args' - dd = dircmp().new(args[0], args[1]) - dd.run() - if ('-r', '') in options: - dd.report_phase4_closure() - else: - dd.report() - -# demo() + """Demonstration and testing.""" + + import sys + import getopt + options, args = getopt.getopt(sys.argv[1:], 'r') + if len(args) <> 2: raise getopt.error, 'need exactly two args' + dd = dircmp().new(args[0], args[1]) + dd.run() + if ('-r', '') in options: + dd.report_phase4_closure() + else: + dd.report() + +if __name__ == "__main__": + demo() diff --git a/Lib/fpformat.py b/Lib/fpformat.py index 74f5698..523f3ce 100644 --- a/Lib/fpformat.py +++ b/Lib/fpformat.py @@ -1,15 +1,15 @@ -# General floating point formatting functions. +"""General floating point formatting functions. -# Functions: -# fix(x, digits_behind) -# sci(x, digits_behind) +Functions: +fix(x, digits_behind) +sci(x, digits_behind) -# Each takes a number or a string and a number of digits as arguments. - -# Parameters: -# x: number to be formatted; or a string resembling a number -# digits_behind: number of digits behind the decimal point +Each takes a number or a string and a number of digits as arguments. +Parameters: +x: number to be formatted; or a string resembling a number +digits_behind: number of digits behind the decimal point +""" import re |