diff options
Diffstat (limited to 'Lib')
63 files changed, 2596 insertions, 881 deletions
diff --git a/Lib/UserList.py b/Lib/UserList.py index 9fbcc02..1c8a622 100644 --- a/Lib/UserList.py +++ b/Lib/UserList.py @@ -1,11 +1,9 @@ # A more or less complete user-defined wrapper around list objects class UserList: - def __init__(self, *args): - if len(args) > 1: raise TypeError, 'too many args' + def __init__(self, list = None): self.data = [] - if args: - list = args[0] + if list is not None: if type(list) == type(self.data): self.data[:] = list else: diff --git a/Lib/aifc.py b/Lib/aifc.py index aa1e56c..c1418be 100644 --- a/Lib/aifc.py +++ b/Lib/aifc.py @@ -179,7 +179,10 @@ def _read_short(file): def _read_string(file): length = ord(file.read(1)) - data = file.read(length) + if length == 0: + data = '' + else: + data = file.read(length) if length & 1 == 0: dummy = file.read(1) return data diff --git a/Lib/audiodev.py b/Lib/audiodev.py index d0dcfed..02d63f7 100644 --- a/Lib/audiodev.py +++ b/Lib/audiodev.py @@ -1,28 +1,40 @@ -import AL, SUNAUDIODEV - error = 'audiodev.error' class Play_Audio_sgi: # Private instance variables access frameratelist, nchannelslist, sampwidthlist, oldparams, \ params, config, inited_outrate, inited_width, \ - inited_nchannels, port, converter: private - - frameratelist = [(48000, AL.RATE_48000), - (44100, AL.RATE_44100), - (32000, AL.RATE_32000), - (22050, AL.RATE_22050), - (16000, AL.RATE_16000), - (11025, AL.RATE_11025), - ( 8000, AL.RATE_8000)] - nchannelslist = [(1, AL.MONO), - (2, AL.STEREO)] - sampwidthlist = [(1, AL.SAMPLE_8), - (2, AL.SAMPLE_16), - (3, AL.SAMPLE_24)] + inited_nchannels, port, converter, classinited: private + + classinited = 0 + frameratelist = nchannelslist = sampwidthlist = None + + def initclass(self): + import AL + Play_Audio_sgi.frameratelist = [ + (48000, AL.RATE_48000), + (44100, AL.RATE_44100), + (32000, AL.RATE_32000), + (22050, AL.RATE_22050), + (16000, AL.RATE_16000), + (11025, AL.RATE_11025), + ( 8000, AL.RATE_8000), + ] + Play_Audio_sgi.nchannelslist = [ + (1, AL.MONO), + (2, AL.STEREO), + ] + Play_Audio_sgi.sampwidthlist = [ + (1, AL.SAMPLE_8), + (2, AL.SAMPLE_16), + (3, AL.SAMPLE_24), + ] + Play_Audio_sgi.classinited = 1 def __init__(self): - import al + import al, AL + if not self.classinited: + self.initclass() self.oldparams = [] self.params = [AL.OUTPUT_RATE, 0] self.config = al.newconfig() @@ -37,7 +49,7 @@ class Play_Audio_sgi: if self.port: self.stop() if self.oldparams: - import al + import al, AL al.setparams(AL.DEFAULT_DEVICE, self.oldparams) self.oldparams = [] @@ -54,7 +66,7 @@ class Play_Audio_sgi: self.port.closeport() self.port = None if self.oldparams: - import al + import al, AL al.setparams(AL.DEFAULT_DEVICE, self.oldparams) self.oldparams = [] @@ -75,6 +87,7 @@ class Play_Audio_sgi: break else: if width == 0: + import AL self.inited_width = 0 self.config.setwidth(AL.SAMPLE_16) self.converter = self.ulaw2lin @@ -94,7 +107,7 @@ class Play_Audio_sgi: if not (self.inited_outrate and self.inited_nchannels): raise error, 'params not specified' if not self.port: - import al + import al, AL self.port = al.openport('Python', 'w', self.config) self.oldparams = self.params[:] al.getparams(AL.DEFAULT_DEVICE, self.oldparams) @@ -156,7 +169,7 @@ class Play_Audio_sun: if not (self.inited_outrate and self.inited_width and self.inited_nchannels): raise error, 'params not specified' if not self.port: - import sunaudiodev + import sunaudiodev, SUNAUDIODEV self.port = sunaudiodev.open('w') info = self.port.getinfo() info.o_sample_rate = self.outrate @@ -17,6 +17,8 @@ class Bdb: # Basic Debugger self.breaks = {} def reset(self): + import linecache + linecache.checkcache() self.botframe = None self.stopframe = None self.returnframe = None @@ -134,11 +136,35 @@ class Bdb: # Basic Debugger self.returnframe = frame self.quitting = 0 + def set_trace(self): + # Start debugging from here + try: + 1 + '' + except: + frame = sys.exc_traceback.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_traceback.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 @@ -177,7 +203,7 @@ class Bdb: # Basic Debugger return 'There are no breakpoints in that file!' del self.breaks[filename] - def clear_all_breaks(self, filename, lineno): + def clear_all_breaks(self): if not self.breaks: return 'There are no breakpoints!' self.breaks = {} @@ -217,11 +243,14 @@ class Bdb: # Basic Debugger # def format_stack_entry(self, frame_lineno): - import codehack, linecache, repr, string + import linecache, repr, string frame, lineno = frame_lineno filename = frame.f_code.co_filename s = filename + '(' + `lineno` + ')' - s = s + codehack.getcodename(frame.f_code) + 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__'] if args is not None: @@ -269,17 +298,19 @@ class Bdb: # Basic Debugger sys.settrace(None) +def set_trace(): + Bdb().set_trace() + # -------------------- testing -------------------- class Tdb(Bdb): def user_call(self, frame, args): - import codehack - name = codehack.getcodename(frame.f_code) + name = frame.f_code.co_name if not name: name = '???' print '+++ call', name, args def user_line(self, frame): - import linecache, string, codehack - name = codehack.getcodename(frame.f_code) + import linecache, string + name = frame.f_code.co_name if not name: name = '???' fn = frame.f_code.co_filename line = linecache.getline(fn, frame.f_lineno) @@ -300,7 +331,5 @@ def bar(a): return a/2 def test(): - import linecache - linecache.checkcache() t = Tdb() t.run('import bdb; bdb.foo(10)') diff --git a/Lib/calendar.py b/Lib/calendar.py index 4dfcf0c8..e9b1644 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -106,12 +106,7 @@ def weekheader(width): return str # Print a month's calendar -def prmonth(year, month, *rest): - if rest[2:]: raise TypeError, 'too many args' - w = 0 - l = 0 - if rest[0:]: w = rest[0] - if rest[1:]: l = rest[1] +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), @@ -56,8 +56,36 @@ class Cmd: else: import newdir names = newdir.dir(self.__class__) - cmds = [] + cmds_doc = [] + cmds_undoc = [] + help = {} + for name in names: + if name[:5] == 'help_': + help[name[5:]]=1 for name in names: if name[:3] == 'do_': - cmds.append(name[3:]) - print cmds + cmd=name[3:] + if help.has_key(cmd): + cmds_doc.append(cmd) + del help[cmd] + else: + cmds_undoc.append(cmd) + print + self.print_topics("Documented commands (type help " \ + "<topic>):",cmds_doc, 15, 80) + self.print_topics("Miscellaneous help topics:", + help.keys(), 15, 80) + self.print_topics("Undocumented commands:", + cmds_undoc, 15, 80) + + def print_topics(self, header, cmds, cmdlen, maxcol): + if cmds: + print header; + print "="*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" diff --git a/Lib/codehack.py b/Lib/codehack.py index d00d2bf..1f16814 100644 --- a/Lib/codehack.py +++ b/Lib/codehack.py @@ -7,6 +7,10 @@ import string import os import linecache +# XXX The functions getcodename() and getfuncname() are now obsolete +# XXX as code and function objects now have a name attribute -- +# XXX co.co_name and f.func_name. + # Extract the function or class name from a code object. # This is a bit of a hack, since a code object doesn't contain # the name directly. So what do we do: @@ -135,7 +135,8 @@ def_op('BREAK_LOOP', 80) def_op('RAISE_EXCEPTION', 81) def_op('LOAD_LOCALS', 82) def_op('RETURN_VALUE', 83) - +def_op('LOAD_GLOBALS', 84) +def_op('EXEC_STMT', 85) def_op('BUILD_FUNCTION', 86) def_op('POP_BLOCK', 87) def_op('END_FINALLY', 88) @@ -173,6 +174,7 @@ jrel_op('FOR_LOOP', 114) # Number of bytes to skip name_op('LOAD_LOCAL', 115) # Index in name list name_op('LOAD_GLOBAL', 116) # Index in name list +def_op('SET_FUNC_ARGS', 117) # Argcount jrel_op('SETUP_LOOP', 120) # Distance to target address jrel_op('SETUP_EXCEPT', 121) # "" diff --git a/Lib/ftplib.py b/Lib/ftplib.py index c441f1f..d160303 100644 --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -9,10 +9,7 @@ # >>> from ftplib import FTP # >>> ftp = FTP('ftp.cwi.nl') # connect to host, default port # >>> ftp.login() # default, i.e.: user anonymous, passwd user@hostname -# >>> def handle_one_line(line): # callback for ftp.retrlines -# ... print line -# ... -# >>> ftp.retrlines('LIST', handle_one_line) # list directory contents +# >>> ftp.retrlines('LIST') # list directory contents # total 43 # d--x--x--x 2 root root 512 Jul 1 16:50 bin # d--x--x--x 2 root root 512 Sep 16 1991 etc @@ -20,7 +17,7 @@ # drwxr-srwt 15 root ftp 10240 Nov 5 20:43 pub # >>> ftp.quit() # -# To download a file, use ftp.retrlines('RETR ' + filename, handle_one_line), +# To download a file, use ftp.retrlines('RETR ' + filename), # or ftp.retrbinary() with slightly different arguments. # To upload a file, use ftp.storlines() or ftp.storbinary(), which have # an open file as argument. @@ -30,9 +27,14 @@ import os import sys -import socket import string +# Import SOCKS module if it exists, else standard socket module socket +try: + import SOCKS; socket = SOCKS +except ImportError: + import socket + # Magic number from <socket.h> MSG_OOB = 0x1 # Process data out of band @@ -59,14 +61,6 @@ all_errors = (error_reply, error_temp, error_perm, error_proto, \ CRLF = '\r\n' -# Next port to be used by makeport(), with PORT_OFFSET added -# (This is now only used when the python interpreter doesn't support -# the getsockname() method yet) -nextport = 0 -PORT_OFFSET = 40000 -PORT_CYCLE = 1000 - - # The class itself class FTP: @@ -74,7 +68,7 @@ class FTP: # Initialize host to localhost, port to standard ftp port # Optional arguments are host (for connect()), # and user, passwd, acct (for login()) - def __init__(self, *args): + def __init__(self, host = '', user = '', passwd = '', acct = ''): # Initialize the instance to something mostly harmless self.debugging = 0 self.host = '' @@ -82,18 +76,16 @@ class FTP: self.sock = None self.file = None self.welcome = None - if args: - self.connect(args[0]) - if args[1:]: - apply(self.login, args[1:]) + if host: + self.connect(host) + if user: self.login(user, passwd, acct) # Connect to host. Arguments: # - host: hostname to connect to (default previous host) # - port: port to connect to (default previous port) - def connect(self, *args): - if args: self.host = args[0] - if args[1:]: self.port = args[1] - if args[2:]: raise TypeError, 'too many args' + def connect(self, host = '', port = 0): + if host: self.host = host + if port: self.port = port self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect(self.host, self.port) self.file = self.sock.makefile('r') @@ -208,19 +200,8 @@ class FTP: def makeport(self): global nextport sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - getsockname = sock.getsockname - except AttributeError: - if self.debugging > 1: - print '*** getsockname not supported', - print '-- using manual port assignment ***' - port = nextport + PORT_OFFSET - nextport = (nextport + 1) % PORT_CYCLE - sock.bind('', port) - getsockname = None - sock.listen(0) # Assigns the port if not explicitly bound - if getsockname: - host, port = getsockname() + sock.listen(1) + host, port = sock.getsockname() resp = self.sendport(port) return sock @@ -235,13 +216,7 @@ class FTP: return conn # Login, default anonymous - def login(self, *args): - user = passwd = acct = '' - n = len(args) - if n > 3: raise TypeError, 'too many arguments' - if n > 0: user = args[0] - if n > 1: passwd = args[1] - if n > 2: acct = args[2] + def login(self, user = '', passwd = '', acct = ''): if not user: user = 'anonymous' if user == 'anonymous' and passwd in ('', '-'): thishost = socket.gethostname() @@ -278,11 +253,7 @@ class FTP: # The callback function is called for each line, with trailing # CRLF stripped. This creates a new port for you. # print_lines is the default callback - def retrlines(self, cmd, *args): - callback = None - if args: - callback = args[0] - if args[1:]: raise TypeError, 'too many args' + def retrlines(self, cmd, callback = None): if not callback: callback = print_line resp = self.sendcmd('TYPE A') conn = self.transfercmd(cmd) @@ -423,30 +394,22 @@ def print_line(line): # Usage: ftp [-d] host [-l[dir]] [-d[dir]] [file] ... def test(): import marshal - global nextport - try: - nextport = marshal.load(open('.@nextport', 'r')) - except IOError: - pass - try: - debugging = 0 - while sys.argv[1] == '-d': - debugging = debugging+1 - del sys.argv[1] - host = sys.argv[1] - ftp = FTP(host) - ftp.set_debuglevel(debugging) - ftp.login() - for file in sys.argv[2:]: - if file[:2] == '-l': - ftp.dir(file[2:]) - elif file[:2] == '-d': - cmd = 'CWD' - if file[2:]: cmd = cmd + ' ' + file[2:] - resp = ftp.sendcmd(cmd) - else: - ftp.retrbinary('RETR ' + file, \ - sys.stdout.write, 1024) - ftp.quit() - finally: - marshal.dump(nextport, open('.@nextport', 'w')) + debugging = 0 + while sys.argv[1] == '-d': + debugging = debugging+1 + del sys.argv[1] + host = sys.argv[1] + ftp = FTP(host) + ftp.set_debuglevel(debugging) + ftp.login() + for file in sys.argv[2:]: + if file[:2] == '-l': + ftp.dir(file[2:]) + elif file[:2] == '-d': + cmd = 'CWD' + if file[2:]: cmd = cmd + ' ' + file[2:] + resp = ftp.sendcmd(cmd) + else: + ftp.retrbinary('RETR ' + file, \ + sys.stdout.write, 1024) + ftp.quit() diff --git a/Lib/irix5/FCNTL.py b/Lib/irix5/FCNTL.py index 1271b9e..12c60fa 100755 --- a/Lib/irix5/FCNTL.py +++ b/Lib/irix5/FCNTL.py @@ -1,35 +1,35 @@ -# These lines were generated by h2py.py (see demo/scripts) -# from <sys/fcntl.h> on Irix 4.0.2. -# The applicability on other systems is not clear. - +# Generated by h2py from /usr/include/sys/fcntl.h FNDELAY = 0x04 FAPPEND = 0x08 FSYNC = 0x10 -FRCACH = 0x20 -FASYNC = 0x40 -FNONBLK = 0x80 -FCREAT = 0x100 -FTRUNC = 0x200 -FEXCL = 0x400 -FNOCTTY = 0x800 +FNONBLOCK = 0x80 +FASYNC = 0x1000 +FNONBLK = FNONBLOCK +FDIRECT = 0x8000 +FCREAT = 0x0100 +FTRUNC = 0x0200 +FEXCL = 0x0400 +FNOCTTY = 0x0800 O_RDONLY = 0 O_WRONLY = 1 O_RDWR = 2 -O_ACCMODE = 0x3 -O_NDELAY = FNDELAY -O_APPEND = FAPPEND -O_SYNC = FSYNC -O_NONBLOCK = FNONBLK -O_CREAT = FCREAT -O_TRUNC = FTRUNC -O_EXCL = FEXCL -O_NOCTTY = FNOCTTY +O_NDELAY = 0x04 +O_APPEND = 0x08 +O_SYNC = 0x10 +O_NONBLOCK = 0x80 +O_DIRECT = 0x8000 +O_CREAT = 0x100 +O_TRUNC = 0x200 +O_EXCL = 0x400 +O_NOCTTY = 0x800 F_DUPFD = 0 F_GETFD = 1 F_SETFD = 2 F_GETFL = 3 F_SETFL = 4 -F_GETLK = 5 +F_GETLK = 14 +F_O_GETLK = 5 +F_GETLK = 14 F_SETLK = 6 F_SETLKW = 7 F_CHKFL = 8 @@ -37,13 +37,17 @@ F_ALLOCSP = 10 F_FREESP = 11 F_SETBSDLK = 12 F_SETBSDLKW = 13 -F_RGETLK = 20 -F_RSETLK = 21 +F_DIOINFO = 30 +F_RSETLK = 20 +F_RGETLK = 21 F_RSETLKW = 22 -F_GETOWN = 10 -F_SETOWN = 11 +F_GETOWN = 23 +F_SETOWN = 24 +F_O_GETOWN = 10 +F_O_SETOWN = 11 F_RDLCK = 01 F_WRLCK = 02 F_UNLCK = 03 -FD_CLOEXEC = 0x1 -FD_NODUP_FORK = 0x2 +O_ACCMODE = 3 +FD_CLOEXEC = 1 +FD_NODUP_FORK = 4 diff --git a/Lib/irix5/IN.py b/Lib/irix5/IN.py index 78be3ef..325a021 100755 --- a/Lib/irix5/IN.py +++ b/Lib/irix5/IN.py @@ -1,8 +1,4 @@ -# Symbolic constants from <netinet/in.h>. -# These constants are SGI specific! -# See demo/scripts/h2py.py for a tool to help generate a version for -# your system. - +# Generated by h2py from /usr/include/netinet/in.h IPPROTO_IP = 0 IPPROTO_ICMP = 1 IPPROTO_IGMP = 2 @@ -14,6 +10,8 @@ IPPROTO_UDP = 17 IPPROTO_IDP = 22 IPPROTO_TP = 29 IPPROTO_XTP = 36 +IPPROTO_HELLO = 63 +IPPROTO_ND = 77 IPPROTO_EON = 80 IPPROTO_RAW = 255 IPPROTO_MAX = 256 @@ -42,6 +40,11 @@ INADDR_MAX_LOCAL_GROUP = 0xe00000ff INADDR_NONE = 0xffffffff IN_LOOPBACKNET = 127 IP_OPTIONS = 1 +IP_MULTICAST_IF = 2 +IP_MULTICAST_TTL = 3 +IP_MULTICAST_LOOP = 4 +IP_ADD_MEMBERSHIP = 5 +IP_DROP_MEMBERSHIP = 6 IP_HDRINCL = 7 IP_TOS = 8 IP_TTL = 9 @@ -49,11 +52,32 @@ IP_RECVOPTS = 10 IP_RECVRETOPTS = 11 IP_RECVDSTADDR = 12 IP_RETOPTS = 13 -IP_MULTICAST_IF = 2 -IP_MULTICAST_TTL = 3 -IP_MULTICAST_LOOP = 4 -IP_ADD_MEMBERSHIP = 5 -IP_DROP_MEMBERSHIP = 6 +IP_OPTIONS = 1 +IP_HDRINCL = 2 +IP_TOS = 3 +IP_TTL = 4 +IP_RECVOPTS = 5 +IP_RECVRETOPTS = 6 +IP_RECVDSTADDR = 7 +IP_RETOPTS = 8 +IP_MULTICAST_IF = 20 +IP_MULTICAST_TTL = 21 +IP_MULTICAST_LOOP = 22 +IP_ADD_MEMBERSHIP = 23 +IP_DROP_MEMBERSHIP = 24 +IRIX4_IP_OPTIONS = 1 +IRIX4_IP_MULTICAST_IF = 2 +IRIX4_IP_MULTICAST_TTL = 3 +IRIX4_IP_MULTICAST_LOOP = 4 +IRIX4_IP_ADD_MEMBERSHIP = 5 +IRIX4_IP_DROP_MEMBERSHIP = 6 +IRIX4_IP_HDRINCL = 7 +IRIX4_IP_TOS = 8 +IRIX4_IP_TTL = 9 +IRIX4_IP_RECVOPTS = 10 +IRIX4_IP_RECVRETOPTS = 11 +IRIX4_IP_RECVDSTADDR = 12 +IRIX4_IP_RETOPTS = 13 IP_DEFAULT_MULTICAST_TTL = 1 IP_DEFAULT_MULTICAST_LOOP = 1 IP_MAX_MEMBERSHIPS = 20 diff --git a/Lib/irix5/SOCKET.py b/Lib/irix5/SOCKET.py index 8a15ef9..0ba0742 100755 --- a/Lib/irix5/SOCKET.py +++ b/Lib/irix5/SOCKET.py @@ -1,8 +1,23 @@ +# Generated by h2py from /usr/include/sys/socket.h SOCK_STREAM = 1 SOCK_DGRAM = 2 SOCK_RAW = 3 SOCK_RDM = 4 SOCK_SEQPACKET = 5 +NC_TPI_CLTS = 1 +NC_TPI_COTS = 2 +NC_TPI_COTS_ORD = 3 +NC_TPI_RAW = 4 +SOCK_DGRAM = NC_TPI_CLTS +SOCK_STREAM = NC_TPI_COTS +SOCK_RAW = NC_TPI_RAW +SOCK_RDM = 5 +SOCK_SEQPACKET = 6 +IRIX4_SOCK_STREAM = 1 +IRIX4_SOCK_DGRAM = 2 +IRIX4_SOCK_RAW = 3 +IRIX4_SOCK_RDM = 4 +IRIX4_SOCK_SEQPACKET = 5 SO_DEBUG = 0x0001 SO_ACCEPTCONN = 0x0002 SO_REUSEADDR = 0x0004 @@ -13,6 +28,9 @@ SO_USELOOPBACK = 0x0040 SO_LINGER = 0x0080 SO_OOBINLINE = 0x0100 SO_REUSEPORT = 0x0200 +SO_ORDREL = 0x0200 +SO_IMASOCKET = 0x0400 +SO_CHAMELEON = 0x1000 SO_SNDBUF = 0x1001 SO_RCVBUF = 0x1002 SO_SNDLOWAT = 0x1003 @@ -21,6 +39,7 @@ SO_SNDTIMEO = 0x1005 SO_RCVTIMEO = 0x1006 SO_ERROR = 0x1007 SO_TYPE = 0x1008 +SO_PROTOTYPE = 0x1009 SOL_SOCKET = 0xffff AF_UNSPEC = 0 AF_UNIX = 1 @@ -30,7 +49,6 @@ AF_PUP = 4 AF_CHAOS = 5 AF_NS = 6 AF_ISO = 7 -AF_OSI = AF_ISO AF_ECMA = 8 AF_DATAKIT = 9 AF_CCITT = 10 @@ -44,7 +62,14 @@ AF_ROUTE = 17 AF_RAW = 18 AF_LINK = 18 pseudo_AF_XTP = 19 -AF_MAX = 20 +AF_NIT = 17 +AF_802 = 18 +AF_OSI = 19 +AF_X25 = 20 +AF_OSINET = 21 +AF_GOSIP = 22 +AF_SDL = 23 +AF_MAX = (AF_SDL+1) PF_UNSPEC = AF_UNSPEC PF_UNIX = AF_UNIX PF_INET = AF_INET @@ -53,7 +78,6 @@ PF_PUP = AF_PUP PF_CHAOS = AF_CHAOS PF_NS = AF_NS PF_ISO = AF_ISO -PF_OSI = AF_ISO PF_ECMA = AF_ECMA PF_DATAKIT = AF_DATAKIT PF_CCITT = AF_CCITT @@ -67,11 +91,18 @@ PF_ROUTE = AF_ROUTE PF_LINK = AF_LINK PF_XTP = pseudo_AF_XTP PF_RAW = AF_RAW +PF_NIT = AF_NIT +PF_802 = AF_802 +PF_OSI = AF_OSI +PF_X25 = AF_X25 +PF_OSINET = AF_OSINET +PF_GOSIP = AF_GOSIP PF_MAX = AF_MAX SOMAXCONN = 5 MSG_OOB = 0x1 MSG_PEEK = 0x2 MSG_DONTROUTE = 0x4 +MSG_EOR = 0x8 MSG_BTAG = 0x40 MSG_ETAG = 0x80 MSG_MAXIOVLEN = 16 diff --git a/Lib/irix5/cddb.py b/Lib/irix5/cddb.py index d7fdc96..0dee709 100755 --- a/Lib/irix5/cddb.py +++ b/Lib/irix5/cddb.py @@ -138,6 +138,19 @@ class Cddb: continue self.track[trackno] = value f.close() + for i in range(2, len(self.track)): + track = self.track[i] + # if track title starts with `,', use initial part + # of previous track's title + if track[0] == ',': + try: + off = string.index(self.track[i - 1], + ',') + except string.index_error: + pass + else: + self.track[i] = self.track[i-1][:off] \ + + track def write(self): import posixpath @@ -153,6 +166,17 @@ class Cddb: f.write('album.title:\t' + self.title + '\n') f.write('album.artist:\t' + self.artist + '\n') f.write('album.toc:\t' + self.toc + '\n') + prevpref = None for i in range(1, len(self.track)): - f.write('track' + `i` + '.title:\t' + self.track[i] + '\n') + track = self.track[i] + try: + off = string.index(track, ',') + except string.index_error: + prevpref = None + else: + if prevpref and track[:off] == prevpref: + track = track[off:] + else: + prevpref = track[:off] + f.write('track' + `i` + '.title:\t' + track + '\n') f.close() diff --git a/Lib/irix5/flp.py b/Lib/irix5/flp.py index c3f6f3b..bc4a8ab 100755 --- a/Lib/irix5/flp.py +++ b/Lib/irix5/flp.py @@ -432,10 +432,10 @@ def _select_crfunc(fm, cl): def test(): import time - t0 = time.millitimer() + t0 = time.time() if len(sys.argv) == 2: forms = parse_forms(sys.argv[1]) - t1 = time.millitimer() + t1 = time.time() print 'parse time:', 0.001*(t1-t0), 'sec.' keys = forms.keys() keys.sort() @@ -443,8 +443,8 @@ def test(): _printform(forms[i]) elif len(sys.argv) == 3: form = parse_form(sys.argv[1], sys.argv[2]) - t1 = time.millitimer() - print 'parse time:', 0.001*(t1-t0), 'sec.' + t1 = time.time() + print 'parse time:', round(t1-t0, 3), 'sec.' _printform(form) else: print 'Usage: test fdfile [form]' diff --git a/Lib/lib-old/codehack.py b/Lib/lib-old/codehack.py index d00d2bf..1f16814 100644 --- a/Lib/lib-old/codehack.py +++ b/Lib/lib-old/codehack.py @@ -7,6 +7,10 @@ import string import os import linecache +# XXX The functions getcodename() and getfuncname() are now obsolete +# XXX as code and function objects now have a name attribute -- +# XXX co.co_name and f.func_name. + # Extract the function or class name from a code object. # This is a bit of a hack, since a code object doesn't contain # the name directly. So what do we do: diff --git a/Lib/lib-old/newdir.py b/Lib/lib-old/newdir.py index 26a7df0..937c49e 100644 --- a/Lib/lib-old/newdir.py +++ b/Lib/lib-old/newdir.py @@ -65,11 +65,9 @@ def is_function(x): # Approximation of builtin dir(); but note that this lists the user's # variables by default, not the current local name space. -def dir(*args): - if len(args) > 0: - if len(args) == 1: - args = args[0] - return listattrs(args) +def dir(x = None): + if x is not None: + return listattrs(x) else: import __main__ return listattrs(__main__) diff --git a/Lib/lib-old/packmail.py b/Lib/lib-old/packmail.py index d612c88..13b1bdc 100644 --- a/Lib/lib-old/packmail.py +++ b/Lib/lib-old/packmail.py @@ -41,12 +41,28 @@ def packsome(outfp, dirname, names): # Pack all files from a directory def packall(outfp, dirname): names = os.listdir(dirname) + try: + names.remove('.') + except: + pass + try: + names.remove('..') + except: + pass names.sort() packsome(outfp, dirname, names) # Pack all files from a directory that are not older than a give one def packnotolder(outfp, dirname, oldest): names = os.listdir(dirname) + try: + names.remove('.') + except: + pass + try: + names.remove('..') + except: + pass oldest = os.path.join(dirname, oldest) st = os.stat(oldest) mtime = st[ST_MTIME] @@ -67,6 +83,14 @@ def packtree(outfp, dirname): print 'packtree', dirname outfp.write('mkdir ' + unixfix(dirname) + '\n') names = os.listdir(dirname) + try: + names.remove('.') + except: + pass + try: + names.remove('..') + except: + pass subdirs = [] for name in names: fullname = os.path.join(dirname, name) diff --git a/Lib/lib-stdwin/WindowSched.py b/Lib/lib-stdwin/WindowSched.py index 56ca6f8..b2fbe76 100644 --- a/Lib/lib-stdwin/WindowSched.py +++ b/Lib/lib-stdwin/WindowSched.py @@ -1,5 +1,5 @@ # Combine a real-time scheduling queue and stdwin event handling. -# Uses the millisecond timer. +# Keeps times in milliseconds. import stdwin, stdwinq from stdwinevents import WE_TIMER @@ -19,11 +19,11 @@ def delayfunc(msecs): mainloop.dispatch(event) return # - # Use millisleep for very short delays or if there are no windows + # Use sleep for very short delays or if there are no windows # if msecs < 100 or mainloop.countwindows() == 0: if msecs > 0: - time.millisleep(msecs) + time.sleep(msecs * 0.001) return # # Post a timer event on an arbitrary window and wait for it @@ -35,7 +35,10 @@ def delayfunc(msecs): if event[0] <> WE_TIMER: mainloop.dispatch(event) -q = sched.scheduler(time.millitimer, delayfunc) +def millitimer(): + return int(1000 * time.time()) + +q = sched.scheduler(millitimer, delayfunc) # Export functions enter, enterabs and cancel just like a scheduler # diff --git a/Lib/lib-stdwin/filewin.py b/Lib/lib-stdwin/filewin.py index a03c3f7..df6aa7d 100644 --- a/Lib/lib-stdwin/filewin.py +++ b/Lib/lib-stdwin/filewin.py @@ -2,19 +2,19 @@ # File windows, a subclass of textwin (which is a subclass of gwin) import textwin -import builtin +import __builtin__ # FILE WINDOW def open_readonly(fn): # Open a file window - fp = builtin.open(fn, 'r') + fp = __builtin__.open(fn, 'r') w = textwin.open_readonly(fn, fp.read()) w.fn = fn return w def open(fn): # Open a file window - fp = builtin.open(fn, 'r') + fp = __builtin__.open(fn, 'r') w = textwin.open(fn, fp.read()) w.fn = fn return w diff --git a/Lib/lib-stdwin/wdb.py b/Lib/lib-stdwin/wdb.py index d5c28bb..4018ab1 100644 --- a/Lib/lib-stdwin/wdb.py +++ b/Lib/lib-stdwin/wdb.py @@ -241,7 +241,7 @@ class Wdb(bdb.Bdb, basewin.BaseWindow): # Window debugger stdwin.fleep() def draw(self, detail): - import linecache, codehack, string + import linecache, string d = self.win.begindrawing() try: h, v = 0, 0 @@ -252,7 +252,7 @@ class Wdb(bdb.Bdb, basewin.BaseWindow): # Window debugger else: s = ' ' s = s + fn + '(' + `lineno` + ')' - s = s + codehack.getcodename(f.f_code) + s = s + f.f_code.co_name if f.f_locals.has_key('__args__'): args = f.f_locals['__args__'] if args is not None: @@ -286,6 +286,8 @@ def runcall(*args): try: apply(x.runcall, args) finally: x.close() +def set_trace(): + Wdb().set_trace() # Post-Mortem interface @@ -304,6 +306,4 @@ def pm(): TESTCMD = 'import x; x.main()' def test(): - import linecache - linecache.checkcache() run(TESTCMD) diff --git a/Lib/mimetools.py b/Lib/mimetools.py index 2a076f0..2844fa4 100644 --- a/Lib/mimetools.py +++ b/Lib/mimetools.py @@ -1,8 +1,10 @@ # Various tools used by MIME-reading or MIME-writing programs. -import string +import os import rfc822 +import string +import tempfile # A derived class of rfc822.Message that knows about MIME headers and @@ -67,7 +69,7 @@ class Message(rfc822.Message): def getencoding(self): if self.encodingheader == None: return '7bit' - return self.encodingheader + return string.lower(self.encodingheader) def gettype(self): return self.type @@ -110,3 +112,75 @@ def choose_boundary(): timestamp = `int(time.time())` seed = `rand.rand()` return _prefix + '.' + timestamp + '.' + seed + + +# Subroutines for decoding some common content-transfer-types + +# XXX This requires that uudecode and mmencode are in $PATH + +def decode(input, output, encoding): + if decodetab.has_key(encoding): + pipethrough(input, decodetab[encoding], output) + else: + raise ValueError, \ + 'unknown Content-Transfer-Encoding: %s' % encoding + +def encode(input, output, encoding): + if encodetab.has_key(encoding): + pipethrough(input, encodetab[encoding], output) + else: + raise ValueError, \ + 'unknown Content-Transfer-Encoding: %s' % encoding + +uudecode_pipe = '''( +TEMP=/tmp/@uu.$$ +sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode +cat $TEMP +rm $TEMP +)''' + +decodetab = { + 'uuencode': uudecode_pipe, + 'x-uuencode': uudecode_pipe, + 'quoted-printable': 'mmencode -u -q', + 'base64': 'mmencode -u -b', +} + +encodetab = { + 'x-uuencode': 'uuencode tempfile', + 'uuencode': 'uuencode tempfile', + 'quoted-printable': 'mmencode -q', + 'base64': 'mmencode -b', +} + +def pipeto(input, command): + pipe = os.popen(command, 'w') + copyliteral(input, pipe) + pipe.close() + +def pipethrough(input, command, output): + tempname = tempfile.mktemp() + try: + temp = open(tempname, 'w') + except IOError: + print '*** Cannot create temp file', `tempname` + return + copyliteral(input, temp) + temp.close() + pipe = os.popen(command + ' <' + tempname, 'r') + copybinary(pipe, output) + pipe.close() + os.unlink(tempname) + +def copyliteral(input, output): + while 1: + line = input.readline() + if not line: break + output.write(line) + +def copybinary(input, output): + BUFSIZE = 8192 + while 1: + line = input.read(BUFSIZE) + if not line: break + output.write(line) diff --git a/Lib/multifile.py b/Lib/multifile.py index 7a52ab6..71e0dd0 100644 --- a/Lib/multifile.py +++ b/Lib/multifile.py @@ -85,6 +85,17 @@ class MultiFile: err('*** Missing endmarker in MultiFile.readline()\n') return '' # + def readlines(self): + list = [] + while 1: + line = self.readline() + if not line: break + list.append(line) + return list + # + def read(self): # Note: no size argument -- read until EOF only! + return string.joinfields(self.readlines(), '') + # def next(self): while self.readline(): pass if self.level > 1 or self.last: diff --git a/Lib/newdir.py b/Lib/newdir.py index 26a7df0..937c49e 100644 --- a/Lib/newdir.py +++ b/Lib/newdir.py @@ -65,11 +65,9 @@ def is_function(x): # Approximation of builtin dir(); but note that this lists the user's # variables by default, not the current local name space. -def dir(*args): - if len(args) > 0: - if len(args) == 1: - args = args[0] - return listattrs(args) +def dir(x = None): + if x is not None: + return listattrs(x) else: import __main__ return listattrs(__main__) diff --git a/Lib/nntplib.py b/Lib/nntplib.py index e7f0627..fb08b0c 100644 --- a/Lib/nntplib.py +++ b/Lib/nntplib.py @@ -60,10 +60,7 @@ class NNTP: # - host: hostname to connect to # - port: port to connect to (default the standard NNTP port) - def __init__(self, host, *args): - if len(args) > 1: raise TypeError, 'too many args' - if args: port = args[0] - else: port = NNTP_PORT + def __init__(self, host, port = NNTP_PORT): self.host = host self.port = port self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) diff --git a/Lib/ospath.py b/Lib/ospath.py index 866d02e..1e66759 100644 --- a/Lib/ospath.py +++ b/Lib/ospath.py @@ -1,15 +1,3 @@ -# ospath.py is to {posix,mac}path.py what os.py is to modules {posix,mac} - -try: - import posix - name = 'posix' - del posix -except ImportError: - import mac - name = 'mac' - del mac - -if name == 'posix': - from posixpath import * -elif name == 'mac': - from macpath import * +# ospath.py is obsolete +import os +exec 'from %s import *' % os.name diff --git a/Lib/packmail.py b/Lib/packmail.py index d612c88..13b1bdc 100644 --- a/Lib/packmail.py +++ b/Lib/packmail.py @@ -41,12 +41,28 @@ def packsome(outfp, dirname, names): # Pack all files from a directory def packall(outfp, dirname): names = os.listdir(dirname) + try: + names.remove('.') + except: + pass + try: + names.remove('..') + except: + pass names.sort() packsome(outfp, dirname, names) # Pack all files from a directory that are not older than a give one def packnotolder(outfp, dirname, oldest): names = os.listdir(dirname) + try: + names.remove('.') + except: + pass + try: + names.remove('..') + except: + pass oldest = os.path.join(dirname, oldest) st = os.stat(oldest) mtime = st[ST_MTIME] @@ -67,6 +83,14 @@ def packtree(outfp, dirname): print 'packtree', dirname outfp.write('mkdir ' + unixfix(dirname) + '\n') names = os.listdir(dirname) + try: + names.remove('.') + except: + pass + try: + names.remove('..') + except: + pass subdirs = [] for name in names: fullname = os.path.join(dirname, name) diff --git a/Lib/pdb.doc b/Lib/pdb.doc index c92b572..43a91c2 100644 --- a/Lib/pdb.doc +++ b/Lib/pdb.doc @@ -61,9 +61,10 @@ u(p) Move the current frame one level up in the stack trace (to a newer frame). -b(reak) [lineno] - With a line number argument, set a break there in the current file. - Without argument, list all breaks. +b(reak) [lineno | function] + With a line number argument, set a break there in the current + file. With a function name, set a break at the entry of that + function. Without argument, list all breaks. cl(ear) [lineno] With a line number argument, clear that break in the current file. @@ -74,17 +74,31 @@ class Pdb(bdb.Bdb, cmd.Cmd): # Return true to exit from the command loop do_h = cmd.Cmd.do_help - + def do_break(self, arg): if not arg: print self.get_all_breaks() # XXX return - try: + # Try line number as argument + try: lineno = int(eval(arg)) + filename = self.curframe.f_code.co_filename except: - print '*** Error in argument:', `arg` - return - filename = self.curframe.f_code.co_filename + # Try function name as the argument + import codehack + try: + func = eval(arg, self.curframe.f_globals, + self.curframe.f_locals) + if hasattr(func, 'im_func'): + func = func.im_func + code = func.func_code + except: + print '*** Could not eval argument:', arg + return + lineno = codehack.getlineno(code) + filename = code.co_filename + + # now set the break point err = self.set_break(filename, lineno) if err: print '***', err do_b = do_break @@ -159,10 +173,10 @@ class Pdb(bdb.Bdb, cmd.Cmd): do_q = do_quit def do_args(self, arg): - if self.curframe.f_locals.has_key('__return__'): - print `self.curframe.f_locals['__return__']` + if self.curframe.f_locals.has_key('__args__'): + print `self.curframe.f_locals['__args__']` else: - print '*** Not arguments?!' + print '*** No arguments?!' do_a = do_args def do_retval(self, arg): @@ -229,7 +243,6 @@ class Pdb(bdb.Bdb, cmd.Cmd): do_l = do_list def do_whatis(self, arg): - import codehack try: value = eval(arg, self.curframe.f_globals, \ self.curframe.f_locals) @@ -241,13 +254,13 @@ class Pdb(bdb.Bdb, cmd.Cmd): try: code = value.func_code except: pass if code: - print 'Function', codehack.getcodename(code) + print 'Function', code.co_name return # Is it an instance method? try: code = value.im_func.func_code except: pass if code: - print 'Method', codehack.getcodename(code) + print 'Method', code.co_name return # None of the above... print type(value) @@ -276,6 +289,137 @@ class Pdb(bdb.Bdb, cmd.Cmd): print self.format_stack_entry(frame_lineno) + # Help methods (derived from pdb.doc) + + def help_help(self): + self.help_h() + + def help_h(self): + print """h(elp) + Without argument, print the list of available commands. + With a command name as argument, print help about that command + "help pdb" pipes the full documentation file to the $PAGER + "help exec" gives help on the ! command""" + + def help_where(self): + self.help_w() + + def help_w(self): + print """w(here) + Print a stack trace, with the most recent frame at the bottom. + An arrow indicates the "current frame", which determines the + context of most commands.""" + + def help_down(self): + self.help_d() + + def help_d(self): + print """d(own) + Move the current frame one level down in the stack trace + (to an older frame).""" + + def help_up(self): + self.help_u() + + def help_u(self): + print """u(p) + Move the current frame one level up in the stack trace + (to a newer frame).""" + + def help_break(self): + self.help_b() + + def help_b(self): + print """b(reak) [lineno | function] + With a line number argument, set a break there in the current + file. With a function name, set a break at the entry of that + function. Without argument, list all breaks.""" + + def help_clear(self): + self.help_cl() + + def help_cl(self): + print """cl(ear) [lineno] + With a line number argument, clear that break in the current file. + Without argument, clear all breaks (but first ask confirmation).""" + + def help_step(self): + self.help_s() + + def help_s(self): + print """s(tep) + Execute the current line, stop at the first possible occasion + (either in a function that is called or in the current function).""" + + def help_next(self): + self.help_n() + + def help_n(self): + print """n(ext) + Continue execution until the next line in the current function + is reached or it returns.""" + + def help_return(self): + self.help_r() + + def help_r(self): + print """r(eturn) + Continue execution until the current function returns.""" + + def help_continue(self): + self.help_c() + + def help_cont(self): + self.help_c() + + def help_c(self): + print """c(ont(inue)) + Continue execution, only stop when a breakpoint is encountered.""" + + def help_list(self): + self.help_l() + + def help_l(self): + print """l(ist) [first [,last]] + List source code for the current file. + Without arguments, list 11 lines around the current line + or continue the previous listing. + With one argument, list 11 lines starting at that line. + With two arguments, list the given range; + if the second argument is less than the first, it is a count.""" + + def help_args(self): + self.help_a() + + def help_a(self): + print """a(rgs) + Print the argument list of the current function.""" + + def help_p(self): + print """p expression + Print the value of the expression.""" + + def help_exec(self): + print """(!) statement + Execute the (one-line) statement in the context of + the current stack frame. + The exclamation point can be omitted unless the first word + of the statement resembles a debugger command. + To assign to a global variable you must always prefix the + command with a 'global' command, e.g.: + (Pdb) global list_options; list_options = ['-l'] + (Pdb)""" + + def help_quit(self): + self.help_q() + + def help_q(self): + print """q(uit) Quit from the debugger. + The program being executed is aborted.""" + + def help_pdb(self): + help() + # Simplified interface def run(statement): @@ -287,6 +431,8 @@ def runctx(statement, globals, locals): def runcall(*args): apply(Pdb().runcall, args) +def set_trace(): + Pdb().set_trace() # Post-Mortem interface @@ -306,8 +452,6 @@ def pm(): TESTCMD = 'import x; x.main()' def test(): - import linecache - linecache.checkcache() run(TESTCMD) # print help diff --git a/Lib/plat-irix5/FCNTL.py b/Lib/plat-irix5/FCNTL.py index 1271b9e..12c60fa 100755 --- a/Lib/plat-irix5/FCNTL.py +++ b/Lib/plat-irix5/FCNTL.py @@ -1,35 +1,35 @@ -# These lines were generated by h2py.py (see demo/scripts) -# from <sys/fcntl.h> on Irix 4.0.2. -# The applicability on other systems is not clear. - +# Generated by h2py from /usr/include/sys/fcntl.h FNDELAY = 0x04 FAPPEND = 0x08 FSYNC = 0x10 -FRCACH = 0x20 -FASYNC = 0x40 -FNONBLK = 0x80 -FCREAT = 0x100 -FTRUNC = 0x200 -FEXCL = 0x400 -FNOCTTY = 0x800 +FNONBLOCK = 0x80 +FASYNC = 0x1000 +FNONBLK = FNONBLOCK +FDIRECT = 0x8000 +FCREAT = 0x0100 +FTRUNC = 0x0200 +FEXCL = 0x0400 +FNOCTTY = 0x0800 O_RDONLY = 0 O_WRONLY = 1 O_RDWR = 2 -O_ACCMODE = 0x3 -O_NDELAY = FNDELAY -O_APPEND = FAPPEND -O_SYNC = FSYNC -O_NONBLOCK = FNONBLK -O_CREAT = FCREAT -O_TRUNC = FTRUNC -O_EXCL = FEXCL -O_NOCTTY = FNOCTTY +O_NDELAY = 0x04 +O_APPEND = 0x08 +O_SYNC = 0x10 +O_NONBLOCK = 0x80 +O_DIRECT = 0x8000 +O_CREAT = 0x100 +O_TRUNC = 0x200 +O_EXCL = 0x400 +O_NOCTTY = 0x800 F_DUPFD = 0 F_GETFD = 1 F_SETFD = 2 F_GETFL = 3 F_SETFL = 4 -F_GETLK = 5 +F_GETLK = 14 +F_O_GETLK = 5 +F_GETLK = 14 F_SETLK = 6 F_SETLKW = 7 F_CHKFL = 8 @@ -37,13 +37,17 @@ F_ALLOCSP = 10 F_FREESP = 11 F_SETBSDLK = 12 F_SETBSDLKW = 13 -F_RGETLK = 20 -F_RSETLK = 21 +F_DIOINFO = 30 +F_RSETLK = 20 +F_RGETLK = 21 F_RSETLKW = 22 -F_GETOWN = 10 -F_SETOWN = 11 +F_GETOWN = 23 +F_SETOWN = 24 +F_O_GETOWN = 10 +F_O_SETOWN = 11 F_RDLCK = 01 F_WRLCK = 02 F_UNLCK = 03 -FD_CLOEXEC = 0x1 -FD_NODUP_FORK = 0x2 +O_ACCMODE = 3 +FD_CLOEXEC = 1 +FD_NODUP_FORK = 4 diff --git a/Lib/plat-irix5/IN.py b/Lib/plat-irix5/IN.py index 78be3ef..325a021 100755 --- a/Lib/plat-irix5/IN.py +++ b/Lib/plat-irix5/IN.py @@ -1,8 +1,4 @@ -# Symbolic constants from <netinet/in.h>. -# These constants are SGI specific! -# See demo/scripts/h2py.py for a tool to help generate a version for -# your system. - +# Generated by h2py from /usr/include/netinet/in.h IPPROTO_IP = 0 IPPROTO_ICMP = 1 IPPROTO_IGMP = 2 @@ -14,6 +10,8 @@ IPPROTO_UDP = 17 IPPROTO_IDP = 22 IPPROTO_TP = 29 IPPROTO_XTP = 36 +IPPROTO_HELLO = 63 +IPPROTO_ND = 77 IPPROTO_EON = 80 IPPROTO_RAW = 255 IPPROTO_MAX = 256 @@ -42,6 +40,11 @@ INADDR_MAX_LOCAL_GROUP = 0xe00000ff INADDR_NONE = 0xffffffff IN_LOOPBACKNET = 127 IP_OPTIONS = 1 +IP_MULTICAST_IF = 2 +IP_MULTICAST_TTL = 3 +IP_MULTICAST_LOOP = 4 +IP_ADD_MEMBERSHIP = 5 +IP_DROP_MEMBERSHIP = 6 IP_HDRINCL = 7 IP_TOS = 8 IP_TTL = 9 @@ -49,11 +52,32 @@ IP_RECVOPTS = 10 IP_RECVRETOPTS = 11 IP_RECVDSTADDR = 12 IP_RETOPTS = 13 -IP_MULTICAST_IF = 2 -IP_MULTICAST_TTL = 3 -IP_MULTICAST_LOOP = 4 -IP_ADD_MEMBERSHIP = 5 -IP_DROP_MEMBERSHIP = 6 +IP_OPTIONS = 1 +IP_HDRINCL = 2 +IP_TOS = 3 +IP_TTL = 4 +IP_RECVOPTS = 5 +IP_RECVRETOPTS = 6 +IP_RECVDSTADDR = 7 +IP_RETOPTS = 8 +IP_MULTICAST_IF = 20 +IP_MULTICAST_TTL = 21 +IP_MULTICAST_LOOP = 22 +IP_ADD_MEMBERSHIP = 23 +IP_DROP_MEMBERSHIP = 24 +IRIX4_IP_OPTIONS = 1 +IRIX4_IP_MULTICAST_IF = 2 +IRIX4_IP_MULTICAST_TTL = 3 +IRIX4_IP_MULTICAST_LOOP = 4 +IRIX4_IP_ADD_MEMBERSHIP = 5 +IRIX4_IP_DROP_MEMBERSHIP = 6 +IRIX4_IP_HDRINCL = 7 +IRIX4_IP_TOS = 8 +IRIX4_IP_TTL = 9 +IRIX4_IP_RECVOPTS = 10 +IRIX4_IP_RECVRETOPTS = 11 +IRIX4_IP_RECVDSTADDR = 12 +IRIX4_IP_RETOPTS = 13 IP_DEFAULT_MULTICAST_TTL = 1 IP_DEFAULT_MULTICAST_LOOP = 1 IP_MAX_MEMBERSHIPS = 20 diff --git a/Lib/plat-irix5/SOCKET.py b/Lib/plat-irix5/SOCKET.py index 8a15ef9..0ba0742 100755 --- a/Lib/plat-irix5/SOCKET.py +++ b/Lib/plat-irix5/SOCKET.py @@ -1,8 +1,23 @@ +# Generated by h2py from /usr/include/sys/socket.h SOCK_STREAM = 1 SOCK_DGRAM = 2 SOCK_RAW = 3 SOCK_RDM = 4 SOCK_SEQPACKET = 5 +NC_TPI_CLTS = 1 +NC_TPI_COTS = 2 +NC_TPI_COTS_ORD = 3 +NC_TPI_RAW = 4 +SOCK_DGRAM = NC_TPI_CLTS +SOCK_STREAM = NC_TPI_COTS +SOCK_RAW = NC_TPI_RAW +SOCK_RDM = 5 +SOCK_SEQPACKET = 6 +IRIX4_SOCK_STREAM = 1 +IRIX4_SOCK_DGRAM = 2 +IRIX4_SOCK_RAW = 3 +IRIX4_SOCK_RDM = 4 +IRIX4_SOCK_SEQPACKET = 5 SO_DEBUG = 0x0001 SO_ACCEPTCONN = 0x0002 SO_REUSEADDR = 0x0004 @@ -13,6 +28,9 @@ SO_USELOOPBACK = 0x0040 SO_LINGER = 0x0080 SO_OOBINLINE = 0x0100 SO_REUSEPORT = 0x0200 +SO_ORDREL = 0x0200 +SO_IMASOCKET = 0x0400 +SO_CHAMELEON = 0x1000 SO_SNDBUF = 0x1001 SO_RCVBUF = 0x1002 SO_SNDLOWAT = 0x1003 @@ -21,6 +39,7 @@ SO_SNDTIMEO = 0x1005 SO_RCVTIMEO = 0x1006 SO_ERROR = 0x1007 SO_TYPE = 0x1008 +SO_PROTOTYPE = 0x1009 SOL_SOCKET = 0xffff AF_UNSPEC = 0 AF_UNIX = 1 @@ -30,7 +49,6 @@ AF_PUP = 4 AF_CHAOS = 5 AF_NS = 6 AF_ISO = 7 -AF_OSI = AF_ISO AF_ECMA = 8 AF_DATAKIT = 9 AF_CCITT = 10 @@ -44,7 +62,14 @@ AF_ROUTE = 17 AF_RAW = 18 AF_LINK = 18 pseudo_AF_XTP = 19 -AF_MAX = 20 +AF_NIT = 17 +AF_802 = 18 +AF_OSI = 19 +AF_X25 = 20 +AF_OSINET = 21 +AF_GOSIP = 22 +AF_SDL = 23 +AF_MAX = (AF_SDL+1) PF_UNSPEC = AF_UNSPEC PF_UNIX = AF_UNIX PF_INET = AF_INET @@ -53,7 +78,6 @@ PF_PUP = AF_PUP PF_CHAOS = AF_CHAOS PF_NS = AF_NS PF_ISO = AF_ISO -PF_OSI = AF_ISO PF_ECMA = AF_ECMA PF_DATAKIT = AF_DATAKIT PF_CCITT = AF_CCITT @@ -67,11 +91,18 @@ PF_ROUTE = AF_ROUTE PF_LINK = AF_LINK PF_XTP = pseudo_AF_XTP PF_RAW = AF_RAW +PF_NIT = AF_NIT +PF_802 = AF_802 +PF_OSI = AF_OSI +PF_X25 = AF_X25 +PF_OSINET = AF_OSINET +PF_GOSIP = AF_GOSIP PF_MAX = AF_MAX SOMAXCONN = 5 MSG_OOB = 0x1 MSG_PEEK = 0x2 MSG_DONTROUTE = 0x4 +MSG_EOR = 0x8 MSG_BTAG = 0x40 MSG_ETAG = 0x80 MSG_MAXIOVLEN = 16 diff --git a/Lib/plat-irix5/cddb.py b/Lib/plat-irix5/cddb.py index d7fdc96..0dee709 100755 --- a/Lib/plat-irix5/cddb.py +++ b/Lib/plat-irix5/cddb.py @@ -138,6 +138,19 @@ class Cddb: continue self.track[trackno] = value f.close() + for i in range(2, len(self.track)): + track = self.track[i] + # if track title starts with `,', use initial part + # of previous track's title + if track[0] == ',': + try: + off = string.index(self.track[i - 1], + ',') + except string.index_error: + pass + else: + self.track[i] = self.track[i-1][:off] \ + + track def write(self): import posixpath @@ -153,6 +166,17 @@ class Cddb: f.write('album.title:\t' + self.title + '\n') f.write('album.artist:\t' + self.artist + '\n') f.write('album.toc:\t' + self.toc + '\n') + prevpref = None for i in range(1, len(self.track)): - f.write('track' + `i` + '.title:\t' + self.track[i] + '\n') + track = self.track[i] + try: + off = string.index(track, ',') + except string.index_error: + prevpref = None + else: + if prevpref and track[:off] == prevpref: + track = track[off:] + else: + prevpref = track[:off] + f.write('track' + `i` + '.title:\t' + track + '\n') f.close() diff --git a/Lib/plat-irix5/flp.py b/Lib/plat-irix5/flp.py index c3f6f3b..bc4a8ab 100755 --- a/Lib/plat-irix5/flp.py +++ b/Lib/plat-irix5/flp.py @@ -432,10 +432,10 @@ def _select_crfunc(fm, cl): def test(): import time - t0 = time.millitimer() + t0 = time.time() if len(sys.argv) == 2: forms = parse_forms(sys.argv[1]) - t1 = time.millitimer() + t1 = time.time() print 'parse time:', 0.001*(t1-t0), 'sec.' keys = forms.keys() keys.sort() @@ -443,8 +443,8 @@ def test(): _printform(forms[i]) elif len(sys.argv) == 3: form = parse_form(sys.argv[1], sys.argv[2]) - t1 = time.millitimer() - print 'parse time:', 0.001*(t1-t0), 'sec.' + t1 = time.time() + print 'parse time:', round(t1-t0, 3), 'sec.' _printform(form) else: print 'Usage: test fdfile [form]' diff --git a/Lib/plat-sunos4/FCNTL.py b/Lib/plat-sunos4/FCNTL.py index 0ba5e67..1256d81 100755 --- a/Lib/plat-sunos4/FCNTL.py +++ b/Lib/plat-sunos4/FCNTL.py @@ -1,10 +1,10 @@ +# Generated by h2py from stdin _FOPEN = (-1) _FREAD = 0x0001 _FWRITE = 0x0002 _FNDELAY = 0x0004 _FAPPEND = 0x0008 -_FMARK = 0x0010 -_FDEFER = 0x0020 +_FSETBLK = 0x0010 _FASYNC = 0x0040 _FSHLOCK = 0x0080 _FEXLOCK = 0x0100 @@ -15,6 +15,8 @@ _FNBIO = 0x1000 _FSYNC = 0x2000 _FNONBLOCK = 0x4000 _FNOCTTY = 0x8000 +_FMARK = 0x10000 +_FDEFER = 0x20000 O_RDONLY = 0 O_WRONLY = 1 O_RDWR = 2 @@ -25,7 +27,6 @@ O_EXCL = _FEXCL O_NONBLOCK = _FNONBLOCK O_NOCTTY = _FNOCTTY O_SYNC = _FSYNC -O_ACCMODE = (O_RDONLY|O_WRONLY|O_RDWR) FAPPEND = _FAPPEND FSYNC = _FSYNC FASYNC = _FASYNC @@ -36,6 +37,7 @@ FREAD = _FREAD FWRITE = _FWRITE FMARK = _FMARK FDEFER = _FDEFER +FSETBLK = _FSETBLK FSHLOCK = _FSHLOCK FEXLOCK = _FEXLOCK FOPEN = _FOPEN @@ -62,3 +64,4 @@ F_RDLCK = 1 F_WRLCK = 2 F_UNLCK = 3 F_UNLKSYS = 4 +O_ACCMODE = (O_RDONLY|O_WRONLY|O_RDWR) diff --git a/Lib/plat-sunos4/IN.py b/Lib/plat-sunos4/IN.py index 05188af..a05a944 100755 --- a/Lib/plat-sunos4/IN.py +++ b/Lib/plat-sunos4/IN.py @@ -1,8 +1,4 @@ -# Symbolic constants from <netinet/in.h>. -# These constants are SunOS specific! (Possibly even SunOS 4.1.1) -# See demo/scripts/h2py.py for a tool to help generate a version for -# your system. - +# Generated by h2py from /usr/include/netinet/in.h IPPROTO_IP = 0 IPPROTO_ICMP = 1 IPPROTO_IGMP = 2 diff --git a/Lib/plat-sunos4/SOCKET.py b/Lib/plat-sunos4/SOCKET.py index c1b8542..65ce4bc 100755 --- a/Lib/plat-sunos4/SOCKET.py +++ b/Lib/plat-sunos4/SOCKET.py @@ -1,3 +1,4 @@ +# Generated by h2py from /usr/include/sys/socket.h SOCK_STREAM = 1 SOCK_DGRAM = 2 SOCK_RAW = 3 diff --git a/Lib/plat-sunos4/WAIT.py b/Lib/plat-sunos4/WAIT.py new file mode 100755 index 0000000..43612f0 --- /dev/null +++ b/Lib/plat-sunos4/WAIT.py @@ -0,0 +1,13 @@ +# Generated by h2py from /usr/include/sys/wait.h +WUNTRACED = 0004 +WNOHANG = 0100 +WEXITED = 0001 +WTRAPPED = 0002 +WSTOPPED = WUNTRACED +WCONTINUED = 0010 +WNOWAIT = 0200 +WOPTMASK = (WEXITED|WTRAPPED|WSTOPPED|WCONTINUED|WNOHANG|WNOWAIT) +WSTOPFLG = 0177 +WCONTFLG = 0177777 +WCOREFLG = 0200 +WSIGMASK = 0177 diff --git a/Lib/plat-sunos4/regen b/Lib/plat-sunos4/regen index f1482db..8b52d74 100755 --- a/Lib/plat-sunos4/regen +++ b/Lib/plat-sunos4/regen @@ -8,4 +8,5 @@ set -v h2py </usr/include/sys/fcntlcom.h >FCNTL.py echo "O_ACCMODE = (O_RDONLY|O_WRONLY|O_RDWR)" >>FCNTL.py h2py /usr/include/sys/socket.h +h2py /usr/include/sys/wait.h h2py -i '(u_long)' /usr/include/netinet/in.h diff --git a/Lib/posixpath.py b/Lib/posixpath.py index 96116d1..6110f8e 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -130,7 +130,7 @@ def isdir(path): # Is a path a regular file? -# This follows symbolic links, so both islink() and isdir() can be true +# This follows symbolic links, so both islink() and isfile() can be true # for the same path. def isfile(path): @@ -205,7 +205,7 @@ def walk(top, func, arg): for name in names: if name not in exceptions: name = join(top, name) - if isdir(name): + if isdir(name) and not islink(name): walk(name, func, arg) @@ -239,29 +239,35 @@ def expanduser(path): # Expand paths containing shell variable substitutions. -# This is done by piping it through the shell. -# Shell quoting characters (\ " ' `) are protected by a backslash. -# NB: a future version may avoid starting a subprocess and do the -# substitutions internally. This may slightly change the syntax -# for variables. +# This expands the forms $variable and ${variable} only. +# Non-existant variables are left unchanged. + +_varprog = None def expandvars(path): + global _varprog if '$' not in path: return path - q = '' - for c in path: - if c in ('\\', '"', '\'', '`'): - c = '\\' + c - q = q + c - d = '!' - if q == d: - d = '+' - p = posix.popen('cat <<' + d + '\n' + q + '\n' + d + '\n', 'r') - res = p.read() - del p - if res[-1:] == '\n': - res = res[:-1] - return res + if not _varprog: + import regex + _varprog = regex.compile('$\([a-zA-Z0-9_]+\|{[^}]*}\)') + i = 0 + while 1: + i = _varprog.search(path, i) + if i < 0: + break + name = _varprog.group(1) + j = i + len(_varprog.group(0)) + if name[:1] == '{' and name[-1:] == '}': + name = name[1:-1] + if posix.environ.has_key(name): + tail = path[j:] + path = path[:i] + posix.environ[name] + i = len(path) + path = path + tail + else: + i = j + return path # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B. diff --git a/Lib/profile.doc b/Lib/profile.doc index 753d159..bf5d8e3 100644 --- a/Lib/profile.doc +++ b/Lib/profile.doc @@ -1,74 +1,702 @@ -The Python Profiler - -To use the profiler in its simplest form: - - >>> import profile - >>> profile.run(statement) - -This will execute the statement and print statistics. To get more -information out of the profiler, use: - - >>> import profile - >>> profile.run(statement, dump_file) - -where dump_file is a string naming a file to which the (binary) -profile statistics is to be dumped. The binary format is a dump of a -dictionary. The key is the function name in the format described -above; the value is a tuple consisting of, in order, number of calls, -total time spent in the function, total time spent in the function and -all functions called from it, a list of functions called by this -function, and a list of functions that called this function. The dump -can be read back using the following code: - - >>> import marshal - >>> f = open(dump_file, 'r') - >>> dict = marshal.load(f) - >>> f.close() - -An easier way of doing this is by using the class `Stats' which is -also defined in profile: - - >>> import profile - >>> s = profile.Stats().init(dump_file) - -The following methods are defined for instances of `Stats': - - print_stats() -- Print the statistics in a format similar to - the format profile.run() uses. - print_callers() -- For each function, print all functions - which it calls. - print_callees() -- For each function, print all functions from - which it is called. - sort_stats(n) -- Sort the statistics for subsequent - printing. The argument determines on which - field the output should be sorted. - Possibilities are - -1 function name - 0 number of calls - 1 total time spent in a function - 2 total time spent in a function - plus all functions it called - strip_dirs() -- Strip the directory names off of the file - names which are part of the function names. - This undoes the effect of sort_stats(), but - a subsequent sort_stats() does work. - -The methods sort_stats and strip_dirs may change in the future. - -Output of profile.run(statement) and of the print_stats() method of -the `Stats' class consists of the following fields. - - Number of times the function was called. - Total time spent in the function. - Mean time per function call (second field divided by first). - Total time spent in the function and all functions it called, - recursively. - Mean time time spent in the function and all functions it - called (fourth field divided by first). - Name of the function in the format - <file name>:<line number>(<function name>) - -The output of the print_callers and print_callees methods consists of -the name of the function and the names of all function it called or -was called from. The latter names are followed by a parenthesised -number which is the number of calls for this function. +profile.doc last updated 6/23/94 [by Guido] + + PROFILER DOCUMENTATION and (mini) USER'S MANUAL + +Copyright 1994, by InfoSeek Corporation, all rights reserved. +Written by James Roskind + +Permission to use, copy, modify, and distribute this Python software +and its associated documentation for any purpose (subject to the +restriction in the following sentence) without fee is hereby granted, +provided that the above copyright notice appears in all copies, and +that both that copyright notice and this permission notice appear in +supporting documentation, and that the name of InfoSeek not be used in +advertising or publicity pertaining to distribution of the software +without specific, written prior permission. This permission is +explicitly restricted to the copying and modification of the software +to remain in Python, compiled Python, or other languages (such as C) +wherein the modified or derived code is exclusively imported into a +Python module. + +INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +The profiler was written after only programming in Python for 3 weeks. +As a result, it is probably clumsy code, but I don't know for sure yet +'cause I'm a beginner :-). I did work hard to make the code run fast, +so that profiling would be a reasonable thing to do. I tried not to +repeat code fragments, but I'm sure I did some stuff in really awkward +ways at times. Please send suggestions for improvements to: +jar@infoseek.com. I won't promise *any* support. ...but I'd +appreciate the feedback. + + +SECTION HEADING LIST: + INTRODUCTION + HOW IS THIS profile DIFFERENT FROM THE OLD profile MODULE? + INSTANT USERS MANUAL + WHAT IS DETERMINISTIC PROFILING? + REFERENCE MANUAL + FUNCTION profile.run(string, filename_opt) + CLASS Stats(filename, ...) + METHOD strip_dirs() + METHOD add(filename, ...) + METHOD sort_stats(key, ...) + METHOD reverse_order() + METHOD print_stats(restriction, ...) + METHOD print_callers(restrictions, ...) + METHOD print_callees(restrictions, ...) + METHOD ignore() + LIMITATIONS + CALIBRATION + EXTENSIONS: Deriving Better Profilers + + + +INTRODUCTION + +A "profiler" is a program that describes the run time performance of a +program, providing a variety of statistics. This documentation +describes the profiler functionality provided in the modules +"profile" and "pstats." This profiler provides "deterministic +profiling" of any Python programs. It also provides a series of +report generation tools to allow users to rapidly examine the results +of a profile operation. + + +HOW IS THIS profile DIFFERENT FROM THE OLD profile MODULE? + +The big changes from standard profiling module are that you get more +information, and you pay less CPU time. It's not a trade-off, it's a +trade-up. + +To be specific: + + bugs removed: local stack frame is no longer molested, execution time + is now charged to correct functions, .... + + accuracy increased: profiler execution time is no longer charged to + user's code, calibration for platform is supported, file reads + are not done *by* profiler *during* profiling (and charged to + user's code!), ... + + speed increased: Overhead CPU cost was reduced by more than a factor of + two (perhaps a factor of five), lightweight profiler module is + all that must be loaded, and the report generating module + (pstats) is not needed during profiling. + + recursive functions support: cumulative times in recursive functions + are correctly calculated; recursive entries are counted; ... + + large growth in report generating UI: distinct profiles runs can be added + together forming a comprehensive report; functions that import + statistics take arbitrary lists of files; sorting criteria is now + based on keywords (instead of 4 integer options); reports shows + what functions were profiled as well as what profile file was + referenced; output format has been improved, ... + + +INSTANT USERS MANUAL + +This section is provided for users that "don't want to read the +manual." It provides a very brief overview, and allows a user to +rapidly perform profiling on an existing application. + +To profile an application with a main entry point of "foo()", you +would add the following to your module: + + import profile + profile.run("foo()") + +The above action would cause "foo()" to be run, and a series of +informative lines (the profile) to be printed. The above approach is +most useful when working with the interpreter. If you would like to +save the results of a profile into a file for later examination, you +can supply a file name as the second argument to the run() function: + + import profile + profile.run("foo()", 'fooprof') + +When you wish to review the profile, you should use the methods in the +pstats module. Typically you would load the statistics data as +follows: + + import pstats + p = pstats.Stats('fooprof') + +The class "Stats" (the above code just created an instance of this +class) has a variety of methods for manipulating and printing the data +that was just read into "p". When you ran profile.run() above, what +was printed was the result of three method calls: + + p.strip_dirs().sort_stats(-1).print_stats() + +The first method removed the extraneous path from all the module +names. The second method sorted all the entries according to the +standard module/line/name string that is printed (this is to comply +with the semantics of the old profiler). The third method printed out +all the statistics. You might try the following sort calls: + + p.sort_stats('name') + p.print_stats() + +The first call will actually sort the list by function name, and the +second call will print out the statistics. The following are some +interesting calls to experiment with: + + p.sort_stats('cumulative').print_stats(10) + +This sorts the profile by cumulative time in a function, and then only +prints the ten most significant lines. If you want to understand what +algorithms are taking time, the above line is what you would use. + +If you were looking to see what functions were looping a lot, and +taking a lot of time, you would do: + + p.sort_stats('time').print_stats(10) + +to sort according to time spent within each function, and then print +the statistics for the top ten functions. + +You might also try: + + p.sort_stats('file').print_stats('__init__') + +This will sort all the statistics by file name, and then print out +statistics for only the class init methods ('cause they are spelled +with "__init__" in them). As one final example, you could try: + + p.sort_stats('time', 'cum').print_stats(.5, 'init') + +This line sorts stats with a primary key of time, and a secondary key +of cumulative time, and then prints out some of the statistics. To be +specific, the list is first culled down to 50% (re: .5) of its +original size, then only lines containing "init" are maintained, and +that sub-sub-list is printed. + +If you wondered what functions called the above functions, you could +now (p is still sorted according to the last criteria) do: + + p.print_callers(.5, 'init') + +and you would get a list of callers for each of the listed functions. + +If you want more functionality, you're going to have to read the +manual (or guess) what the following functions do: + + p.print_callees() + p.add('fooprof') + + +WHAT IS DETERMINISTIC PROFILING? + +"Deterministic profiling" is meant to reflect the fact that all +"function call", "function return", and "exception" events are +monitored, and precise timings are made for the intervals between +these events (during which time the user's code is executing). In +contrast, "statistical profiling" (which is not done by this module) +randomly samples the effective instruction pointer, and deduces where +time is being spent. The latter technique traditionally involves less +overhead (as the code does not need to be instrumented), but provides +only relative indications of where time is being spent. + +In Python, since there is an interpreter active during execution, the +presence of instrumented code is not required to do deterministic +profiling. Python automatically provides a hook (optional callback) +for each event. In addition, the interpreted nature of Python tends +to add so much overhead to execution, that deterministic profiling +tends to only add small processing overhead, in typical applications. +The result is that deterministic profiling is not that expensive, but +yet provides extensive run time statistics about the execution of a +Python program. + +Call count statistics can be used to identify bugs in code (surprising +counts), and to identify possible inline-expansion points (high call +counts). Internal time statistics can be used to identify hot loops +that should be carefully optimized. Cumulative time statistics should +be used to identify high level errors in the selection of algorithms. +Note that the unusual handling of cumulative times in this profiler +allows statistics for recursive implementations of algorithms to be +directly compared to iterative implementations. + + +REFERENCE MANUAL + +The primary entry point for the profiler is the global function +profile.run(). It is typically used to create any profile +information. The reports are formatted and printed using methods for +the class pstats.Stats. The following is a description of all of +these standard entry points and functions. For a more in-depth view +of some of the code, consider reading the later section on "Profiler +Extensions," which includes discussion of how to derive "better" +profilers from the classes presented, or reading the source code for +these modules. + + +FUNCTION profile.run(string, filename_opt) + +This function takes a single argument that has can be passed to the +"exec" statement, and an optional file name. In all cases this +routine attempts to "exec" its first argument, and gather profiling +statistics from the execution. If no file name is present, then this +function automatically prints a simple profiling report, sorted by the +standard name string (file/line/function-name) that is presented in +each line. The following is a typical output from such a call: + +cut here---- + + main() + 2706 function calls (2004 primitive calls) in 4.504 CPU seconds + + Ordered by: standard name + + ncalls tottime percall cumtime percall filename:lineno(function) + 2 0.006 0.003 0.953 0.477 pobject.py:75(save_objects) + 43/3 0.533 0.012 0.749 0.250 pobject.py:99(evaluate) + ... + +cut here---- + +The first line indicates that this profile was generated by the call: +profile.run('main()'), and hence the exec'ed string is 'main()'. The +second line indicates that 2706 calls were monitored. Of those calls, +2004 were "primitive." We define "primitive" to mean that the call +was not induced via recursion. The next line: "Ordered by: standard +name", indicates that the text string in the far right column was used +to sort the output. The column headings include: + + "ncalls" for the number of calls, + "tottime" for the total time spent in the given function + (and excluding time made in calls to sub-functions), + "percall" is the quotient of "tottime" divided by "ncalls" + "cumtime" is the total time spent in this and all subfunctions + (i.e., from invocation till exit). This figure is + accurate *even* for recursive functions. + "percall" is the quotient of "cumtime" divided by primitive + calls + "filename:lineno(function)" provides the respective data of + each function + +When there are two numbers in the first column (e.g.: 43/3), then the +latter is the number of primitive calls, and the former is the actual +number of calls. Note that when the function does not recurse, these +two values are the same, and only the single figure is printed. + + +CLASS Stats(filename, ...) + +This class constructor creates an instance of a statistics object from +a filename (or set of filenames). Stats objects are manipulated by +methods, in order to print useful reports. + +The file selected by the above constructor must have been created by +the corresponding version of profile. To be specific, there is *NO* +file compatibility guaranteed with future versions of this profiler, +and there is no compatibility with files produced by other profilers +(e.g., the standard system profiler). + +If several files are provided, all the statistics for identical +functions will be coalesced, so that an overall view of several +processes can be considered in a single report. If additional files +need to be combined with data in an existing Stats object, the add() +method can be used. + + +METHOD strip_dirs() + +This method for the Stats class removes all leading path information +from file names. It is very useful in reducing the size of the +printout to fit within (close to) 80 columns. This method modifies +the object, and the striped information is lost. After performing a +strip operation, the object is considered to have its entries in a +"random" order, as it was just after object initialization and +loading. If strip_dir() causes two function names to be +indistinguishable (i.e., they are on the same line of the same +filename, and have the same function name), then the statistics for +these two entries are accumulated into a single entry. + + +METHOD add(filename, ...) + +This methods of the Stats class accumulates additional profiling +information into the current profiling object. Its arguments should +refer to filenames created my the corresponding version of +profile.run(). Statistics for identically named (re: file, line, +name) functions are automatically accumulated into single function +statistics. + + +METHOD sort_stats(key, ...) + +This method modifies the Stats object by sorting it according to the +supplied criteria. The argument is typically a string identifying the +basis of a sort (example: "time" or "name"). + +When more than one key is provided, then additional keys are used as +secondary criteria when the there is equality in all keys selected +before them. For example, sort_stats('name', 'file') will sort all +the entries according to their function name, and resolve all ties +(identical function names) by sorting by file name. + +Abbreviations can be used for any key names, as long as the +abbreviation is unambiguous. The following are the keys currently +defined: + + Valid Arg Meaning + "calls" call count + "cumulative" cumulative time + "file" file name + "module" file name + "pcalls" primitive call count + "line" line number + "name" function name + "nfl" name/file/line + "stdname" standard name + "time" internal time + +Note that all sorts on statistics are in descending order (placing most +time consuming items first), where as name, file, and line number +searches are in ascending order (i.e., alphabetical). The subtle +distinction between "nfl" and "stdname" is that the standard name is a +sort of the name as printed, which means that the embedded line +numbers get compared in an odd way. For example, lines 3, 20, and 40 +would (if the file names were the same) appear in the string order +"20" "3" and "40". In contrast, "nfl" does a numeric compare of the +line numbers. In fact, sort_stats("nfl") is the same as +sort_stats("name", "file", "line"). + +For compatibility with the standard profiler, the numeric argument -1, +0, 1, and 2 are permitted. They are interpreted as "stdname", +"calls", "time", and "cumulative" respectively. If this old style +format (numeric) is used, only one sort key (the numeric key) will be +used, and additionally arguments will be silently ignored. + + +METHOD reverse_order() + +This method for the Stats class reverses the ordering of the basic +list within the object. This method is provided primarily for +compatibility with the standard profiler. Its utility is questionable +now that ascending vs descending order is properly selected based on +the sort key of choice. + + +METHOD print_stats(restriction, ...) + +This method for the Stats class prints out a report as described in +the profile.run() definition. + +The order of the printing is based on the last sort_stats() operation +done on the object (subject to caveats in add() and strip_dirs()). + +The arguments provided (if any) can be used to limit the list down to +the significant entries. Initially, the list is taken to be the +complete set of profiled functions. Each restriction is either an +integer (to select a count of lines), or a decimal fraction between +0.0 and 1.0 inclusive (to select a percentage of lines), or a regular +expression (to pattern match the standard name that is printed). If +several restrictions are provided, then they are applied sequentially. +For example: + + print_stats(.1, "foo:") + +would first limit the printing to first 10% of list, and then only +print functions that were part of filename ".*foo:". In contrast, the +command: + + print_stats("foo:", .1) + +would limit the list to all functions having file names ".*foo:", and +then proceed to only print the first 10% of them. + + +METHOD print_callers(restrictions, ...) + +This method for the Stats class prints a list of all functions that +called each function in the profiled database. The ordering is +identical to that provided by print_stats(), and the definition of the +restricting argument is also identical. For convenience, a number is +shown in parentheses after each caller to show how many times this +specific call was made. A second non-parenthesized number is the +cumulative time spent in the function at the right. + + +METHOD print_callees(restrictions, ...) + +This method for the Stats class prints a list of all function that +were called by the indicated function. Aside from this reversal of +direction of calls (re: called vs was called by), the arguments and +ordering are identical to the print_callers() method. + + +METHOD ignore() + +This method of the Stats class is used to dispose of the value +returned by earlier methods. All standard methods in this class +return the instance that is being processed, so that the commands can +be strung together. For example: + +pstats.Stats('foofile').strip_dirs().sort_stats('cum').print_stats().ignore() + +would perform all the indicated functions, but it would not return +the final reference to the Stats instance. + + + + +LIMITATIONS + +There are two fundamental limitations on this profiler. The first is +that it relies on the Python interpreter to dispatch "call", "return", +and "exception" events. Compiled C code does not get interpreted, +and hence is "invisible" to the profiler. All time spent in C code +(including builtin functions) will be charged to the Python function +that was invoked the C code. IF the C code calls out to some native +Python code, then those calls will be profiled properly. + +The second limitation has to do with accuracy of timing information. +There is a fundamental problem with deterministic profilers involving +accuracy. The most obvious restriction is that the underlying "clock" +is only ticking at a rate (typically) of about .001 seconds. Hence no +measurements will be more accurate that that underlying clock. If +enough measurements are taken, then the "error" will tend to average +out. Unfortunately, removing this first error induces a second source +of error... + +The second problem is that it "takes a while" from when an event is +dispatched until the profiler's call to get the time actually *gets* +the state of the clock. Similarly, there is a certain lag when +exiting the profiler event handler from the time that the clock's +value was obtained (and then squirreled away), until the user's code +is once again executing. As a result, functions that are called many +times, or call many functions, will typically accumulate this error. +The error that accumulates in this fashion is typically less than the +accuracy of the clock (i.e., less than one clock tick), but it *can* +accumulate and become very significant. This profiler provides a +means of calibrating itself for a give platform so that this error can +be probabilistically (i.e., on the average) removed. After the +profiler is calibrated, it will be more accurate (in a least square +sense), but it will sometimes produce negative numbers (when call +counts are exceptionally low, and the gods of probability work against +you :-). ) Do *NOT* be alarmed by negative numbers in the profile. +They should *only* appear if you have calibrated your profiler, and +the results are actually better than without calibration. + + +CALIBRATION + +The profiler class has a hard coded constant that is added to each +event handling time to compensate for the overhead of calling the time +function, and socking away the results. The following procedure can +be used to obtain this constant for a given platform (see discussion +in LIMITATIONS above). + + import profile + pr = profile.Profile() + pr.calibrate(100) + pr.calibrate(100) + pr.calibrate(100) + +The argument to calibrate() is the number of times to try to do the +sample calls to get the CPU times. If your computer is *very* fast, +you might have to do: + + pr.calibrate(1000) + +or even: + + pr.calibrate(10000) + +The object of this exercise is to get a fairly consistent result. +When you have a consistent answer, you are ready to use that number in +the source code. For a Sun Sparcstation 1000 running Solaris 2.3, the +magical number is about .00053. If you have a choice, you are better +off with a smaller constant, and your results will "less often" show +up as negative in profile statistics. + +The following shows how the trace_dispatch() method in the Profile +class should be modified to install the calibration constant on a Sun +Sparcstation 1000: + + def trace_dispatch(self, frame, event, arg): + t = self.timer() + t = t[0] + t[1] - self.t - .00053 # Calibration constant + + if self.dispatch[event](frame,t): + t = self.timer() + self.t = t[0] + t[1] + else: + r = self.timer() + self.t = r[0] + r[1] - t # put back unrecorded delta + return + +Note that if there is no calibration constant, then the line +containing the callibration constant should simply say: + + t = t[0] + t[1] - self.t # no calibration constant + +You can also achieve the same results using a derived class (and the +profiler will actually run equally fast!!), but the above method is +the simplest to use. I could have made the profiler "self +calibrating", but it would have made the initialization of the +profiler class slower, and would have required some *very* fancy +coding, or else the use of a variable where the constant .00053 was +placed in the code shown. This is a ****VERY**** critical performance +section, and there is no reason to use a variable lookup at this +point, when a constant can be used. + + +EXTENSIONS: Deriving Better Profilers + +The Profile class of profile was written so that derived classes +could be developed to extend the profiler. Rather than describing all +the details of such an effort, I'll just present the following two +examples of derived classes that can be used to do profiling. If the +reader is an avid Python programmer, then it should be possible to use +these as a model and create similar (and perchance better) profile +classes. + +If all you want to do is change how the timer is called, or which +timer function is used, then the basic class has an option for that in +the constructor for the class. Consider passing the name of a +function to call into the constructor: + + pr = profile.Profile(your_time_func) + +The resulting profiler will call your time function instead of +os.times(). The function should return either a single number, or a +list of numbers (like what os.times() returns). If the function +returns a single time number, or the list of returned numbers has +length 2, then you will get an especially fast version of the dispatch +routine. + +Be warned that you *should* calibrate the profiler class for the +timer function that you choose. For most machines, a timer that +returns a lone integer value will provide the best results in terms of +low overhead during profiling. (os.times is *pretty* bad, 'cause it +returns a tuple of floating point values, so all arithmetic is +floating point in the profiler!). If you want to be substitute a +better timer in the cleanest fashion, you should derive a class, and +simply put in the replacement dispatch method that better handles your timer +call, along with the appropriate calibration constant :-). + + +cut here------------------------------------------------------------------ +#**************************************************************************** +# OldProfile class documentation +#**************************************************************************** +# +# The following derived profiler simulates the old style profile, providing +# errant results on recursive functions. The reason for the usefulness of this +# profiler is that it runs faster (i.e., less overhead) than the old +# profiler. It still creates all the caller stats, and is quite +# useful when there is *no* recursion in the user's code. It is also +# a lot more accurate than the old profiler, as it does not charge all +# its overhead time to the user's code. +#**************************************************************************** +class OldProfile(Profile): + def trace_dispatch_exception(self, frame, t): + rt, rtt, rct, rfn, rframe, rcur = self.cur + if rcur and not rframe is frame: + return self.trace_dispatch_return(rframe, t) + return 0 + + def trace_dispatch_call(self, frame, t): + fn = `frame.f_code` + + self.cur = (t, 0, 0, fn, frame, self.cur) + if self.timings.has_key(fn): + tt, ct, callers = self.timings[fn] + self.timings[fn] = tt, ct, callers + else: + self.timings[fn] = 0, 0, {} + return 1 + + def trace_dispatch_return(self, frame, t): + rt, rtt, rct, rfn, frame, rcur = self.cur + rtt = rtt + t + sft = rtt + rct + + pt, ptt, pct, pfn, pframe, pcur = rcur + self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur + + tt, ct, callers = self.timings[rfn] + if callers.has_key(pfn): + callers[pfn] = callers[pfn] + 1 + else: + callers[pfn] = 1 + self.timings[rfn] = tt+rtt, ct + sft, callers + + return 1 + + + def snapshot_stats(self): + self.stats = {} + for func in self.timings.keys(): + tt, ct, callers = self.timings[func] + nor_func = self.func_normalize(func) + nor_callers = {} + nc = 0 + for func_caller in callers.keys(): + nor_callers[self.func_normalize(func_caller)]=\ + callers[func_caller] + nc = nc + callers[func_caller] + self.stats[nor_func] = nc, nc, tt, ct, nor_callers + + + +#**************************************************************************** +# HotProfile class documentation +#**************************************************************************** +# +# This profiler is the fastest derived profile example. It does not +# calculate caller-callee relationships, and does not calculate cumulative +# time under a function. It only calculates time spent in a function, so +# it runs very quickly (re: very low overhead). In truth, the basic +# profiler is so fast, that is probably not worth the savings to give +# up the data, but this class still provides a nice example. +#**************************************************************************** +class HotProfile(Profile): + def trace_dispatch_exception(self, frame, t): + rt, rtt, rfn, rframe, rcur = self.cur + if rcur and not rframe is frame: + return self.trace_dispatch_return(rframe, t) + return 0 + + def trace_dispatch_call(self, frame, t): + self.cur = (t, 0, frame, self.cur) + return 1 + + def trace_dispatch_return(self, frame, t): + rt, rtt, frame, rcur = self.cur + + rfn = `frame.f_code` + + pt, ptt, pframe, pcur = rcur + self.cur = pt, ptt+rt, pframe, pcur + + if self.timings.has_key(rfn): + nc, tt = self.timings[rfn] + self.timings[rfn] = nc + 1, rt + rtt + tt + else: + self.timings[rfn] = 1, rt + rtt + + return 1 + + + def snapshot_stats(self): + self.stats = {} + for func in self.timings.keys(): + nc, tt = self.timings[func] + nor_func = self.func_normalize(func) + self.stats[nor_func] = nc, nc, tt, 0, {} + + + +cut here------------------------------------------------------------------ diff --git a/Lib/profile.py b/Lib/profile.py index 502a4db..35ed63e 100755 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -1,201 +1,392 @@ # -# Class for profiling python code. -# Author: Sjoerd Mullender -# Hacked somewhat by: Guido van Rossum +# Class for profiling python code. rev 1.0 6/2/94 # -# See the accompanying document profile.doc for more information. +# Based on prior profile module by Sjoerd Mullender... +# which was hacked somewhat by: Guido van Rossum +# +# See profile.doc for more information + + +# Copyright 1994, by InfoSeek Corporation, all rights reserved. +# Written by James Roskind +# +# Permission to use, copy, modify, and distribute this Python software +# and its associated documentation for any purpose (subject to the +# restriction in the following sentence) without fee is hereby granted, +# provided that the above copyright notice appears in all copies, and +# that both that copyright notice and this permission notice appear in +# supporting documentation, and that the name of InfoSeek not be used in +# advertising or publicity pertaining to distribution of the software +# without specific, written prior permission. This permission is +# explicitly restricted to the copying and modification of the software +# to remain in Python, compiled Python, or other languages (such as C) +# wherein the modified or derived code is exclusively imported into a +# Python module. +# +# INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY +# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + import sys -import codehack import os +import time import string -import fpformat import marshal + +# Global variables +func_norm_dict = {} +func_norm_counter = 0 +pid_string = `os.getpid()` + + +# Optimized intermodule references +ostimes = os.times + + +# Sample timer for use with +#i_count = 0 +#def integer_timer(): +# global i_count +# i_count = i_count + 1 +# return i_count +#itimes = integer_timer # replace with C coded timer returning integers + +#************************************************************************** +# The following are the static member functions for the profiler class +# Note that an instance of Profile() is *not* needed to call them. +#************************************************************************** + + +# simplified user interface +def run(statement, *args): + prof = Profile() + try: + prof = prof.run(statement) + except SystemExit: + pass + if args: + prof.dump_stats(args[0]) + else: + return prof.print_stats() + +# print help +def help(): + for dirname in sys.path: + fullname = os.path.join(dirname, 'profile.doc') + if os.path.exists(fullname): + sts = os.system('${PAGER-more} '+fullname) + if sts: print '*** Pager exit status:', sts + break + else: + print 'Sorry, can\'t find the help file "profile.doc"', + print 'along the Python search path' + + +#************************************************************************** +# class Profile documentation: +#************************************************************************** +# self.cur is always a tuple. Each such tuple corresponds to a stack +# frame that is currently active (self.cur[-2]). The following are the +# definitions of its members. We use this external "parallel stack" to +# avoid contaminating the program that we are profiling. (old profiler +# used to write into the frames local dictionary!!) Derived classes +# can change the definition of some entries, as long as they leave +# [-2:] intact. +# +# [ 0] = Time that needs to be charged to the parent frame's function. It is +# used so that a function call will not have to access the timing data +# for the parents frame. +# [ 1] = Total time spent in this frame's function, excluding time in +# subfunctions +# [ 2] = Cumulative time spent in this frame's function, including time in +# all subfunctions to this frame. +# [-3] = Name of the function that corresonds to this frame. +# [-2] = Actual frame that we correspond to (used to sync exception handling) +# [-1] = Our parent 6-tuple (corresonds to frame.f_back) +#************************************************************************** +# Timing data for each function is stored as a 5-tuple in the dictionary +# self.timings[]. The index is always the name stored in self.cur[4]. +# The following are the definitions of the members: +# +# [0] = The number of times this function was called, not counting direct +# or indirect recursion, +# [1] = Number of times this function appears on the stack, minus one +# [2] = Total time spent internal to this function +# [3] = Cumulative time that this function was present on the stack. In +# non-recursive functions, this is the total execution time from start +# to finish of each invocation of a function, including time spent in +# all subfunctions. +# [5] = A dictionary indicating for each function name, the number of times +# it was called by us. +#************************************************************************** +# We produce function names via a repr() call on the f_code object during +# profiling. This save a *lot* of CPU time. This results in a string that +# always looks like: +# <code object main at 87090, file "/a/lib/python-local/myfib.py", line 76> +# After we "normalize it, it is a tuple of filename, line, function-name. +# We wait till we are done profiling to do the normalization. +# *IF* this repr format changes, then only the normalization routine should +# need to be fixed. +#************************************************************************** class Profile: - def __init__(self): + def __init__(self, *arg): self.timings = {} - self.debug = None - self.call_level = 0 - self.profile_func = None - self.profiling = 0 + self.cur = None + self.cmd = "" - def profile(self, funcname): - if not self.profile_func: - self.profile_func = {} - self.profile_func[funcname] = 1 + self.dispatch = { \ + 'call' : self.trace_dispatch_call, \ + 'return' : self.trace_dispatch_return, \ + 'exception': self.trace_dispatch_exception, \ + } - def trace_dispatch(self, frame, event, arg): - if event == 'call': - funcname = codehack.getcodename(frame.f_code) - if self.profile_func and not self.profiling: - if self.profile_func.has_key(funcname): - return - self.profiling = 1 - t = os.times() - t = t[0] + t[1] - if frame.f_locals.has_key('__key'): - key = frame.f_locals['__key'] - else: - lineno = codehack.getlineno(frame.f_code) - filename = frame.f_code.co_filename - key = filename + ':' + `lineno` + '(' + funcname + ')' - frame.f_locals['__key'] = key - self.call_level = depth(frame) - self.cur_frame = frame - pframe = frame.f_back - if self.debug: - s0 = 'call: ' + key + ' depth: ' + `self.call_level` + ' time: ' + `t` - if pframe: - if pframe.f_locals.has_key('__key'): - pkey = pframe.f_locals['__key'] - else: - pkey = pframe.f_code.co_filename + \ - ':' + \ - `codehack.getlineno(pframe.f_code)` \ - + '(' + \ - codehack.getcodename(pframe.f_code) \ - + ')' - pframe.f_locals['__key'] = pkey - if self.debug: - s1 = 'parent: ' + pkey - if pframe.f_locals.has_key('__start_time'): - st = pframe.f_locals['__start_time'] - nc, tt, ct, callers, callees = \ - self.timings[pkey] - if self.debug: - s1 = s1+' before: st='+`st`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct` - if callers.has_key(key): - callers[key] = callers[key] + 1 - else: - callers[key] = 1 - if self.debug: - s1 = s1+' after: st='+`st`+' nc='+`nc`+' tt='+`tt+(t-st)`+' ct='+`ct` - self.timings[pkey] = nc, tt + (t - st), ct, callers, callees - if self.timings.has_key(key): - nc, tt, ct, callers, callees = self.timings[key] - else: - nc, tt, ct, callers, callees = 0, 0, 0, {}, {} - if self.debug: - s0 = s0+' before: nc='+`nc`+' tt='+`tt`+' ct='+`ct` - s0 = s0+' after: nc='+`nc+1`+' tt='+`tt`+' ct='+`ct` - if pframe: - if callees.has_key(pkey): - callees[pkey] = callees[pkey] + 1 - else: - callees[pkey] = 1 - self.timings[key] = nc + 1, tt, ct, callers, callees - frame.f_locals['__start_time'] = t - if self.debug: - print s0 - print s1 - return - if event == 'return': - if self.profile_func: - if not self.profiling: - return - if self.profile_func.has_key( \ - codehack.getcodename(frame.f_code)): - self.profiling = 0 - self.call_level = depth(frame) - self.cur_frame = frame - pframe = frame.f_back - if self.debug: - s0 = 'return: ' - else: - s0 = None - self.handle_return(pframe, frame, s0) - return - if event == 'exception': - if self.profile_func and not self.profiling: - return - call_level = depth(frame) - if call_level < self.call_level: - if call_level <> self.call_level - 1: - print 'heh!',call_level,self.call_level - if self.debug: - s0 = 'exception: ' + if not arg: + self.timer = os.times + self.dispatcher = self.trace_dispatch + else: + self.timer = arg[0] + t = self.timer() # test out timer function + try: + if len(t) == 2: + self.dispatcher = self.trace_dispatch else: - s0 = None - self.handle_return(self.cur_frame, frame, s0) - self.call_level = call_level - self.cur_frame = frame - return - print 'profile.Profile.dispatch: unknown debugging event:', - print `event` + self.dispatcher = self.trace_dispatch_r + except: + self.dispatcher = self.trace_dispatch_i + self.t = self.get_time() + self.simulate_call('profiler') + + + def get_time(self): # slow simulation of method to acquire time + t = self.timer() + if type(t) == type(()) or type(t) == type([]): + t = reduce(lambda x,y: x+y, t, 0) + return t + + + # Heavily optimized dispatch routine for os.times() timer + + def trace_dispatch(self, frame, event, arg): + t = self.timer() + t = t[0] + t[1] - self.t # No Calibration constant + # t = t[0] + t[1] - self.t - .00053 # Calibration constant + + if self.dispatch[event](frame,t): + t = self.timer() + self.t = t[0] + t[1] + else: + r = self.timer() + self.t = r[0] + r[1] - t # put back unrecorded delta return - def handle_return(self, pframe, frame, s0): - t = os.times() - t = t[0] + t[1] - if frame.f_locals.has_key('__key'): - key = frame.f_locals['__key'] + + + # Dispatch routine for best timer program (return = scalar integer) + + def trace_dispatch_i(self, frame, event, arg): + t = self.timer() - self.t # - 1 # Integer calibration constant + if self.dispatch[event](frame,t): + self.t = self.timer() + else: + self.t = self.timer() - t # put back unrecorded delta + return + + + # SLOW generic dispatch rountine for timer returning lists of numbers + + def trace_dispatch_l(self, frame, event, arg): + t = self.get_time() - self.t + + if self.dispatch[event](frame,t): + self.t = self.get_time() + else: + self.t = self.get_time()-t # put back unrecorded delta + return + + + def trace_dispatch_exception(self, frame, t): + rt, rtt, rct, rfn, rframe, rcur = self.cur + if (not rframe is frame) and rcur: + return self.trace_dispatch_return(rframe, t) + return 0 + + + def trace_dispatch_call(self, frame, t): + fn = `frame.f_code` + + # The following should be about the best approach, but + # we would need a function that maps from id() back to + # the actual code object. + # fn = id(frame.f_code) + # Note we would really use our own function, which would + # return the code address, *and* bump the ref count. We + # would then fix up the normalize function to do the + # actualy repr(fn) call. + + # The following is an interesting alternative + # It doesn't do as good a job, and it doesn't run as + # fast 'cause repr() is written in C, and this is Python. + #fcode = frame.f_code + #code = fcode.co_code + #if ord(code[0]) == 127: # == SET_LINENO + # # see "opcode.h" in the Python source + # fn = (fcode.co_filename, ord(code[1]) | \ + # ord(code[2]) << 8, fcode.co_name) + #else: + # fn = (fcode.co_filename, 0, fcode.co_name) + + self.cur = (t, 0, 0, fn, frame, self.cur) + if self.timings.has_key(fn): + cc, ns, tt, ct, callers = self.timings[fn] + self.timings[fn] = cc, ns + 1, tt, ct, callers else: - funcname = codehack.getcodename(frame.f_code) - lineno = codehack.getlineno(frame.f_code) - filename = frame.f_code.co_filename - key = filename + ':' + `lineno` + '(' + funcname + ')' - frame.f_locals['__key'] = key - if self.debug: - s0 = s0 + key + ' depth: ' + `self.call_level` + ' time: ' + `t` - if pframe: - if pframe.f_locals.has_key('__key'): - pkey = pframe.f_locals['__key'] - else: - funcname = codehack.getcodename(frame.f_code) - lineno = codehack.getlineno(frame.f_code) - filename = frame.f_code.co_filename - pkey = filename + ':' + `lineno` + '(' + funcname + ')' - pframe.f_locals['__key'] = pkey - if self.debug: - s1 = 'parent: '+pkey - if pframe.f_locals.has_key('__start_time') and \ - self.timings.has_key(pkey): - st = pframe.f_locals['__start_time'] - nc, tt, ct, callers, callees = \ - self.timings[pkey] - if self.debug: - s1 = s1+' before: st='+`st`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct` - s1 = s1+' after: st='+`t`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct+(t-st)` - self.timings[pkey] = \ - nc, tt, ct + (t - st), callers, callees - pframe.f_locals['__start_time'] = t - if self.timings.has_key(key): - nc, tt, ct, callers, callees = self.timings[key] + self.timings[fn] = 0, 0, 0, 0, {} + return 1 + + def trace_dispatch_return(self, frame, t): + # if not frame is self.cur[-2]: raise "Bad return", self.cur[3] + + # Prefix "r" means part of the Returning or exiting frame + # Prefix "p" means part of the Previous or older frame + + rt, rtt, rct, rfn, frame, rcur = self.cur + rtt = rtt + t + sft = rtt + rct + + pt, ptt, pct, pfn, pframe, pcur = rcur + self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur + + cc, ns, tt, ct, callers = self.timings[rfn] + if not ns: + ct = ct + sft + cc = cc + 1 + if callers.has_key(pfn): + callers[pfn] = callers[pfn] + 1 # hack: gather more + # stats such as the amount of time added to ct courtesy + # of this specific call, and the contribution to cc + # courtesy of this call. else: - nc, tt, ct, callers, callees = 0, 0, 0, {}, {} - if frame.f_locals.has_key('__start_time'): - st = frame.f_locals['__start_time'] + callers[pfn] = 1 + self.timings[rfn] = cc, ns - 1, tt+rtt, ct, callers + + return 1 + + # The next few function play with self.cmd. By carefully preloading + # our paralell stack, we can force the profiled result to include + # an arbitrary string as the name of the calling function. + # We use self.cmd as that string, and the resulting stats look + # very nice :-). + + def set_cmd(self, cmd): + if self.cur[-1]: return # already set + self.cmd = cmd + self.simulate_call(cmd) + + class fake_code: + def __init__(self, filename, line, name): + self.co_filename = filename + self.co_line = line + self.co_name = name + self.co_code = '\0' # anything but 127 + + def __repr__(self): + return (self.co_filename, self.co_line, self.co_name) + + class fake_frame: + def __init__(self, code, prior): + self.f_code = code + self.f_back = prior + + def simulate_call(self, name): + code = self.fake_code('profile', 0, name) + if self.cur: + pframe = self.cur[-2] else: - st = t - if self.debug: - s0 = s0+' before: st='+`st`+' nc='+`nc`+' tt='+`tt`+' ct='+`ct` - s0 = s0+' after: nc='+`nc`+' tt='+`tt+(t-st)`+' ct='+`ct+(t-st)` - print s0 - print s1 - self.timings[key] = \ - nc, tt + (t - st), ct + (t - st), callers, callees + pframe = None + frame = self.fake_frame(code, pframe) + a = self.dispatch['call'](frame, 0) + return + + # collect stats from pending stack, including getting final + # timings for self.cmd frame. + + def simulate_cmd_complete(self): + t = self.get_time() - self.t + while self.cur[-1]: + # We *can* cause assertion errors here if + # dispatch_trace_return checks for a frame match! + a = self.dispatch['return'](self.cur[-2], t) + t = 0 + self.t = self.get_time() - t + def print_stats(self): - # Print in reverse order by ct - print_title() - list = [] - for key in self.timings.keys(): - nc, tt, ct, callers, callees = self.timings[key] - if nc == 0: - continue - list.append(ct, tt, nc, key) - list.sort() - list.reverse() - for ct, tt, nc, key in list: - print_line(nc, tt, ct, os.path.basename(key)) + import pstats + pstats.Stats(self).strip_dirs().sort_stats(-1). \ + print_stats() def dump_stats(self, file): f = open(file, 'w') - marshal.dump(self.timings, f) + self.create_stats() + marshal.dump(self.stats, f) f.close() + def create_stats(self): + self.simulate_cmd_complete() + self.snapshot_stats() + + def snapshot_stats(self): + self.stats = {} + for func in self.timings.keys(): + cc, ns, tt, ct, callers = self.timings[func] + nor_func = self.func_normalize(func) + nor_callers = {} + nc = 0 + for func_caller in callers.keys(): + nor_callers[self.func_normalize(func_caller)]=\ + callers[func_caller] + nc = nc + callers[func_caller] + self.stats[nor_func] = cc, nc, tt, ct, nor_callers + + + # Override the following function if you can figure out + # a better name for the binary f_code entries. I just normalize + # them sequentially in a dictionary. It would be nice if we could + # *really* see the name of the underlying C code :-). Sometimes + # you can figure out what-is-what by looking at caller and callee + # lists (and knowing what your python code does). + + def func_normalize(self, func_name): + global func_norm_dict + global func_norm_counter + global func_sequence_num + + if func_norm_dict.has_key(func_name): + return func_norm_dict[func_name] + if type(func_name) == type(""): + long_name = string.split(func_name) + file_name = long_name[6][1:-2] + func = long_name[2] + lineno = long_name[8][:-1] + if '?' == func: # Until I find out how to may 'em... + file_name = 'python' + func_norm_counter = func_norm_counter + 1 + func = pid_string + ".C." + `func_norm_counter` + result = file_name , string.atoi(lineno) , func + else: + result = func_name + func_norm_dict[func_name] = result + return result + + # The following two methods can be called by clients to use # a profiler to profile a statement, given as a string. @@ -203,187 +394,219 @@ class Profile: import __main__ dict = __main__.__dict__ self.runctx(cmd, dict, dict) + return self def runctx(self, cmd, globals, locals): + self.set_cmd(cmd) sys.setprofile(self.trace_dispatch) try: - exec(cmd + '\n', globals, locals) + exec(cmd, globals, locals) finally: sys.setprofile(None) # This method is more useful to profile a single function call. - def runcall(self, func, *args): + self.set_cmd(func.__name__) sys.setprofile(self.trace_dispatch) try: apply(func, args) finally: sys.setprofile(None) + return self -def depth(frame): - d = 0 - while frame: - d = d + 1 - frame = frame.f_back - return d + #****************************************************************** + # The following calculates the overhead for using a profiler. The + # problem is that it takes a fair amount of time for the profiler + # to stop the stopwatch (from the time it recieves an event). + # Similarly, there is a delay from the time that the profiler + # re-starts the stopwatch before the user's code really gets to + # continue. The following code tries to measure the difference on + # a per-event basis. The result can the be placed in the + # Profile.dispatch_event() routine for the given platform. Note + # that this difference is only significant if there are a lot of + # events, and relatively little user code per event. For example, + # code with small functions will typically benefit from having the + # profiler calibrated for the current platform. This *could* be + # done on the fly during init() time, but it is not worth the + # effort. Also note that if too large a value specified, then + # execution time on some functions will actually appear as a + # negative number. It is *normal* for some functions (with very + # low call counts) to have such negative stats, even if the + # calibration figure is "correct." + # + # One alternative to profile-time calibration adjustments (i.e., + # adding in the magic little delta during each event) is to track + # more carefully the number of events (and cumulatively, the number + # of events during sub functions) that are seen. If this were + # done, then the arithmetic could be done after the fact (i.e., at + # display time). Currintly, we track only call/return events. + # These values can be deduced by examining the callees and callers + # vectors for each functions. Hence we *can* almost correct the + # internal time figure at print time (note that we currently don't + # track exception event processing counts). Unfortunately, there + # is currently no similar information for cumulative sub-function + # time. It would not be hard to "get all this info" at profiler + # time. Specifically, we would have to extend the tuples to keep + # counts of this in each frame, and then extend the defs of timing + # tuples to include the significant two figures. I'm a bit fearful + # that this additional feature will slow the heavily optimized + # event/time ratio (i.e., the profiler would run slower, fur a very + # low "value added" feature.) + # + # Plugging in the calibration constant doesn't slow down the + # profiler very much, and the accuracy goes way up. + #************************************************************** + + def calibrate(self, m): + n = m + s = self.timer() + while n: + self.simple() + n = n - 1 + f = self.timer() + my_simple = f[0]+f[1]-s[0]-s[1] + #print "Simple =", my_simple, -class Stats: - def __init__(self, file): - f = open(file, 'r') - self.stats = marshal.load(f) - f.close() - self.stats_list = None + n = m + s = self.timer() + while n: + self.instrumented() + n = n - 1 + f = self.timer() + my_inst = f[0]+f[1]-s[0]-s[1] + # print "Instrumented =", my_inst + avg_cost = (my_inst - my_simple)/m + #print "Delta/call =", avg_cost, "(profiler fixup constant)" + return avg_cost - def print_stats(self): - print_title() - if self.stats_list: - for i in range(len(self.stats_list)): - nc, tt, ct, callers, callees, key = \ - self.stats_list[i] - print_line(nc, tt, ct, key) + # simulate a program with no profiler activity + def simple(self): + a = 1 + pass + + # simulate a program with call/return event processing + def instrumented(self): + a = 1 + self.profiler_simulation(a, a, a) + + # simulate an event processing activity (from user's perspective) + def profiler_simulation(self, x, y, z): + t = self.timer() + t = t[0] + t[1] + self.ut = t + + + +#**************************************************************************** +# OldProfile class documentation +#**************************************************************************** +# +# The following derived profiler simulates the old style profile, providing +# errant results on recursive functions. The reason for the usefulnes of this +# profiler is that it runs faster (i.e., less overhead). It still creates +# all the caller stats, and is quite useful when there is *no* recursion +# in the user's code. +# +# This code also shows how easy it is to create a modified profiler. +#**************************************************************************** +class OldProfile(Profile): + def trace_dispatch_exception(self, frame, t): + rt, rtt, rct, rfn, rframe, rcur = self.cur + if rcur and not rframe is frame: + return self.trace_dispatch_return(rframe, t) + return 0 + + def trace_dispatch_call(self, frame, t): + fn = `frame.f_code` + + self.cur = (t, 0, 0, fn, frame, self.cur) + if self.timings.has_key(fn): + tt, ct, callers = self.timings[fn] + self.timings[fn] = tt, ct, callers else: - for key in self.stats.keys(): - nc, tt, ct, callers, callees = self.stats[key] - print_line(nc, tt, ct, key) - - def print_callers(self): - if self.stats_list: - for i in range(len(self.stats_list)): - nc, tt, ct, callers, callees, key = \ - self.stats_list[i] - print key, - for func in callers.keys(): - print func+'('+`callers[func]`+')', - print + self.timings[fn] = 0, 0, {} + return 1 + + def trace_dispatch_return(self, frame, t): + rt, rtt, rct, rfn, frame, rcur = self.cur + rtt = rtt + t + sft = rtt + rct + + pt, ptt, pct, pfn, pframe, pcur = rcur + self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur + + tt, ct, callers = self.timings[rfn] + if callers.has_key(pfn): + callers[pfn] = callers[pfn] + 1 else: - for key in self.stats.keys(): - nc, tt, ct, callers, callees = self.stats[key] - print key, - for func in callers.keys(): - print func+'('+`callers[func]`+')', - print - - def print_callees(self): - if self.stats_list: - for i in range(len(self.stats_list)): - nc, tt, ct, callers, callees, key = \ - self.stats_list[i] - print key, - for func in callees.keys(): - print func+'('+`callees[func]`+')', - print + callers[pfn] = 1 + self.timings[rfn] = tt+rtt, ct + sft, callers + + return 1 + + + def snapshot_stats(self): + self.stats = {} + for func in self.timings.keys(): + tt, ct, callers = self.timings[func] + nor_func = self.func_normalize(func) + nor_callers = {} + nc = 0 + for func_caller in callers.keys(): + nor_callers[self.func_normalize(func_caller)]=\ + callers[func_caller] + nc = nc + callers[func_caller] + self.stats[nor_func] = nc, nc, tt, ct, nor_callers + + + +#**************************************************************************** +# HotProfile class documentation +#**************************************************************************** +# +# This profiler is the fastest derived profile example. It does not +# calculate caller-callee relationships, and does not calculate cumulative +# time under a function. It only calculates time spent in a function, so +# it runs very quickly (re: very low overhead) +#**************************************************************************** +class HotProfile(Profile): + def trace_dispatch_exception(self, frame, t): + rt, rtt, rfn, rframe, rcur = self.cur + if rcur and not rframe is frame: + return self.trace_dispatch_return(rframe, t) + return 0 + + def trace_dispatch_call(self, frame, t): + self.cur = (t, 0, frame, self.cur) + return 1 + + def trace_dispatch_return(self, frame, t): + rt, rtt, frame, rcur = self.cur + + rfn = `frame.f_code` + + pt, ptt, pframe, pcur = rcur + self.cur = pt, ptt+rt, pframe, pcur + + if self.timings.has_key(rfn): + nc, tt = self.timings[rfn] + self.timings[rfn] = nc + 1, rt + rtt + tt else: - for key in self.stats.keys(): - nc, tt, ct, callers, callees = self.stats[key] - print key, - for func in callees.keys(): - print func+'('+`callees[func]`+')', - print - - def sort_stats(self, field): - stats_list = [] - for key in self.stats.keys(): - t = self.stats[key] - nt = () - for i in range(len(t)): - if i == field: - nt = (t[i],) + nt[:] - else: - nt = nt[:] + (t[i],) - if field == -1: - nt = (key,) + nt - else: - nt = nt + (key,) - stats_list.append(nt) - stats_list.sort() - self.stats_list = [] - for i in range(len(stats_list)): - t = stats_list[i] - if field == -1: - nt = t[1:] + t[0:1] - else: - nt = t[1:] - nt = nt[:field] + t[0:1] + nt[field:] - self.stats_list.append(nt) - - def reverse_order(self): - self.stats_list.reverse() - - def strip_dirs(self): - newstats = {} - for key in self.stats.keys(): - nc, tt, ct, callers, callees = self.stats[key] - newkey = os.path.basename(key) - newcallers = {} - for c in callers.keys(): - newcallers[os.path.basename(c)] = callers[c] - newcallees = {} - for c in callees.keys(): - newcallees[os.path.basename(c)] = callees[c] - newstats[newkey] = nc, tt, ct, newcallers, newcallees - self.stats = newstats - self.stats_list = None - -def print_title(): - print string.rjust('ncalls', 8), - print string.rjust('tottime', 8), - print string.rjust('percall', 8), - print string.rjust('cumtime', 8), - print string.rjust('percall', 8), - print 'filename:lineno(function)' - -def print_line(nc, tt, ct, key): - print string.rjust(`nc`, 8), - print f8(tt), - if nc == 0: - print ' '*8, - else: - print f8(tt/nc), - print f8(ct), - if nc == 0: - print ' '*8, - else: - print f8(ct/nc), - print key + self.timings[rfn] = 1, rt + rtt -def f8(x): - return string.rjust(fpformat.fix(x, 3), 8) + return 1 -# simplified user interface -def run(statement, *args): - prof = Profile() - try: - prof.run(statement) - except SystemExit: - pass - if len(args) == 0: - prof.print_stats() - else: - prof.dump_stats(args[0]) -# test command with debugging -def debug(): - prof = Profile() - prof.debug = 1 - try: - prof.run('import x; x.main()') - except SystemExit: - pass - prof.print_stats() + def snapshot_stats(self): + self.stats = {} + for func in self.timings.keys(): + nc, tt = self.timings[func] + nor_func = self.func_normalize(func) + self.stats[nor_func] = nc, nc, tt, 0, {} -# test command -def test(): - run('import x; x.main()') + -# print help -def help(): - for dirname in sys.path: - fullname = os.path.join(dirname, 'profile.doc') - if os.path.exists(fullname): - sts = os.system('${PAGER-more} '+fullname) - if sts: print '*** Pager exit status:', sts - break - else: - print 'Sorry, can\'t find the help file "profile.doc"', - print 'along the Python search path' +#**************************************************************************** +def Stats(*args): + print 'Report generating functions are in the "pstats" module\a' diff --git a/Lib/regexp.py b/Lib/regexp.py index 6136814..4b5db73 100644 --- a/Lib/regexp.py +++ b/Lib/regexp.py @@ -10,13 +10,7 @@ class Prog: self.prog = regex.compile(pat) finally: xxx = regex.set_syntax(save_syntax) - def match(self, *args): - if len(args) == 2: - str, offset = args - elif len(args) == 1: - str, offset = args[0], 0 - else: - raise TypeError, 'wrong argument count' + def match(self, str, offset = 0): if self.prog.search(str, offset) < 0: return () regs = self.prog.regs diff --git a/Lib/repr.py b/Lib/repr.py index 50ee6c9..2f4a0bf 100644 --- a/Lib/repr.py +++ b/Lib/repr.py @@ -77,6 +77,19 @@ class Repr: j = max(0, self.maxlong-3-i) s = s[:i] + '...' + s[len(s)-j:] return s + def repr_instance(self, x, level): + try: + s = `x` + # Bugs in x.__repr__() can cause arbitrary + # exceptions -- then make up something + except: + return '<' + x.__class__.__name__ + ' instance at ' + \ + hex(id(x))[2:] + '>' + if len(s) > self.maxstring: + i = max(0, (self.maxstring-3)/2) + j = max(0, self.maxstring-3-i) + s = s[:i] + '...' + s[len(s)-j:] + return s aRepr = Repr() repr = aRepr.repr diff --git a/Lib/rfc822.py b/Lib/rfc822.py index 39ab6a6..580102c 100644 --- a/Lib/rfc822.py +++ b/Lib/rfc822.py @@ -1,8 +1,8 @@ # RFC-822 message manipulation class. # # XXX This is only a very rough sketch of a full RFC-822 parser; -# additional methods are needed to parse addresses and dates, and to -# tokenize lines according to various other syntax rules. +# in particular the tokenizing of addresses does not adhere to all the +# quoting rules. # # Directions for use: # @@ -22,6 +22,17 @@ # embedded whitespace (including newlines) exactly as they are # specified in the header, and leave the case of the text unchanged. # +# For addresses and address lists there are functions +# realname, mailaddress = m.getaddr(name) and +# list = m.getaddrlist(name) +# where the latter returns a list of (realname, mailaddr) tuples. +# +# There is also a method +# time = m.getdate(name) +# which parses a Date-like field and returns a time-compatible tuple, +# i.e. a tuple such as returned by time.localtime() or accepted by +# time.mktime(). +# # See the class definition for lower level access methods. # # There are also some utility functions here. @@ -29,6 +40,7 @@ import regex import string +import time class Message: @@ -105,12 +117,13 @@ class Message: # Method to determine whether a line is a legal end of # RFC-822 headers. You may override this method if your - # application wants to bend the rules, e.g. to accept lines - # ending in '\r\n', to strip trailing whitespace, or to - # recognise MH template separators ('--------'). + # application wants to bend the rules, e.g. to strip trailing + # whitespace, or to recognise MH template separators + # ('--------'). For convenience (e.g. for code reading from + # sockets) a line consisting of \r\n also matches. def islast(self, line): - return line == '\n' + return line == '\n' or line == '\r\n' # Look through the list of headers and find all lines matching @@ -178,27 +191,94 @@ class Message: return string.strip(text) - # XXX The next step would be to define self.getaddr(name) - # and self.getaddrlist(name) which would parse a header - # consisting of a single mail address and a number of mail - # addresses, respectively. Lower level functions would be - # parseaddr(string) and parseaddrlist(string). + # Retrieve a single address from a header as a tuple, e.g. + # ('Guido van Rossum', 'guido@cwi.nl'). + + def getaddr(self, name): + data = self.getheader(name) + if not data: + return None, None + return parseaddr(data) + + # Retrieve a list of addresses from a header, where each + # address is a tuple as returned by getaddr(). + + def getaddrlist(self, name): + # XXX This function is not really correct. The split + # on ',' might fail in the case of commas within + # quoted strings. + data = self.getheader(name) + if not data: + return [] + data = string.splitfields(data, ',') + for i in range(len(data)): + data[i] = parseaddr(data[i]) + return data + + # Retrieve a date field from a header as a tuple compatible + # with time.mktime(). + + def getdate(self, name): + data = self.getheader(name) + if not data: + return None + return parsedate(data) + - # XXX Similar, there would be a function self.getdate(name) to - # return a date in canonical form (perhaps a number compatible - # to time.time()) and a function parsedate(string). + # Access as a dictionary (only finds first header of each type): - # XXX The inverses of the parse functions may also be useful. + def __len__(self): + types = {} + for line in self.headers: + if line[0] in string.whitespace: continue + i = string.find(line, ':') + if i > 0: + name = string.lower(line[:i]) + types[name] = None + return len(types) + + def __getitem__(self, name): + value = self.getheader(name) + if value is None: raise KeyError, name + return value + + def has_key(self, name): + value = self.getheader(name) + return value is not None + + def keys(self): + types = {} + for line in self.headers: + if line[0] in string.whitespace: continue + i = string.find(line, ':') + if i > 0: + name = line[:i] + key = string.lower(name) + types[key] = name + return types.values() + def values(self): + values = [] + for name in self.keys(): + values.append(self[name]) + return values + + def items(self): + items = [] + for name in self.keys(): + items.append(name, self[name]) + return items # Utility functions # ----------------- +# XXX Should fix these to be really conformant. +# XXX The inverses of the parse functions may also be useful. + # Remove quotes from a string. -# XXX Should fix this to be really conformant. def unquote(str): if len(str) > 1: @@ -207,3 +287,107 @@ def unquote(str): if str[0] == '<' and str[-1:] == '>': return str[1:-1] return str + + +# Parse an address into (name, address) tuple + +def parseaddr(address): + # This is probably not perfect + address = string.strip(address) + # Case 1: part of the address is in <xx@xx> form. + pos = regex.search('<.*>', address) + if pos >= 0: + name = address[:pos] + address = address[pos:] + length = regex.match('<.*>', address) + name = name + address[length:] + address = address[:length] + else: + # Case 2: part of the address is in (comment) form + pos = regex.search('(.*)', address) + if pos >= 0: + name = address[pos:] + address = address[:pos] + length = regex.match('(.*)', name) + address = address + name[length:] + name = name[:length] + else: + # Case 3: neither. Only an address + name = '' + name = string.strip(name) + address = string.strip(address) + if address and address[0] == '<' and address[-1] == '>': + address = address[1:-1] + if name and name[0] == '(' and name[-1] == ')': + name = name[1:-1] + return name, address + + +# Parse a date field + +_monthnames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', + 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + +def parsedate(data): + # XXX This completely ignores timezone matters at the moment... + data = string.split(data) + if data[0][-1] == ',': + # There's a dayname here. Skip it + del data[0] + if len(data) < 5: + return None + data = data[:5] + [dd, mm, yy, tm, tz] = data + if not mm in _monthnames: + return None + mm = _monthnames.index(mm)+1 + tm = string.splitfields(tm, ':') + if len(tm) == 2: + [thh, tmm] = tm + tss = '0' + else: + [thh, tmm, tss] = tm + try: + yy = string.atoi(yy) + dd = string.atoi(dd) + thh = string.atoi(thh) + tmm = string.atoi(tmm) + tss = string.atoi(tss) + except string.atoi_error: + return None + tuple = (yy, mm, dd, thh, tmm, tss, 0, 0, 0) + return tuple + + +# When used as script, run a small test program. +# The first command line argument must be a filename containing one +# message in RFC-822 format. + +if __name__ == '__main__': + import sys + file = '/ufs/guido/Mail/drafts/,1' + if sys.argv[1:]: file = sys.argv[1] + f = open(file, 'r') + m = Message(f) + print 'From:', m.getaddr('from') + print 'To:', m.getaddrlist('to') + print 'Subject:', m.getheader('subject') + print 'Date:', m.getheader('date') + date = m.getdate('date') + if date: + print 'ParsedDate:', time.asctime(date) + else: + print 'ParsedDate:', None + m.rewindbody() + n = 0 + while f.readline(): + n = n + 1 + print 'Lines:', n + print '-'*70 + print 'len =', len(m) + if m.has_key('Date'): print 'Date =', m['Date'] + if m.has_key('X-Nonsense'): pass + print 'keys =', m.keys() + print 'values =', m.values() + print 'items =', m.items() + diff --git a/Lib/sched.py b/Lib/sched.py index c838bad..60b0a1b 100644 --- a/Lib/sched.py +++ b/Lib/sched.py @@ -6,12 +6,11 @@ # # Each instance is parametrized with two functions, one that is # supposed to return the current time, one that is supposed to -# implement a delay. You can implement fine- or course-grained -# real-time scheduling by substituting time and sleep or millitimer -# and millisleep from the built-in module time, or you can implement -# simulated time by writing your own functions. This can also be -# used to integrate scheduling with STDWIN events; the delay function -# is allowed to modify the queue. Time can be expressed as +# implement a delay. You can implement real-time scheduling by +# substituting time and sleep from built-in module time, or you can +# implement simulated time by writing your own functions. This can +# also be used to integrate scheduling with STDWIN events; the delay +# function is allowed to modify the queue. Time can be expressed as # integers or floating point numbers, as long as it is consistent. # Events are specified by tuples (time, priority, action, argument). diff --git a/Lib/stdwin/WindowSched.py b/Lib/stdwin/WindowSched.py index 56ca6f8..b2fbe76 100755 --- a/Lib/stdwin/WindowSched.py +++ b/Lib/stdwin/WindowSched.py @@ -1,5 +1,5 @@ # Combine a real-time scheduling queue and stdwin event handling. -# Uses the millisecond timer. +# Keeps times in milliseconds. import stdwin, stdwinq from stdwinevents import WE_TIMER @@ -19,11 +19,11 @@ def delayfunc(msecs): mainloop.dispatch(event) return # - # Use millisleep for very short delays or if there are no windows + # Use sleep for very short delays or if there are no windows # if msecs < 100 or mainloop.countwindows() == 0: if msecs > 0: - time.millisleep(msecs) + time.sleep(msecs * 0.001) return # # Post a timer event on an arbitrary window and wait for it @@ -35,7 +35,10 @@ def delayfunc(msecs): if event[0] <> WE_TIMER: mainloop.dispatch(event) -q = sched.scheduler(time.millitimer, delayfunc) +def millitimer(): + return int(1000 * time.time()) + +q = sched.scheduler(millitimer, delayfunc) # Export functions enter, enterabs and cancel just like a scheduler # diff --git a/Lib/stdwin/filewin.py b/Lib/stdwin/filewin.py index a03c3f7..df6aa7d 100755 --- a/Lib/stdwin/filewin.py +++ b/Lib/stdwin/filewin.py @@ -2,19 +2,19 @@ # File windows, a subclass of textwin (which is a subclass of gwin) import textwin -import builtin +import __builtin__ # FILE WINDOW def open_readonly(fn): # Open a file window - fp = builtin.open(fn, 'r') + fp = __builtin__.open(fn, 'r') w = textwin.open_readonly(fn, fp.read()) w.fn = fn return w def open(fn): # Open a file window - fp = builtin.open(fn, 'r') + fp = __builtin__.open(fn, 'r') w = textwin.open(fn, fp.read()) w.fn = fn return w diff --git a/Lib/stdwin/wdb.py b/Lib/stdwin/wdb.py index d5c28bb..4018ab1 100755 --- a/Lib/stdwin/wdb.py +++ b/Lib/stdwin/wdb.py @@ -241,7 +241,7 @@ class Wdb(bdb.Bdb, basewin.BaseWindow): # Window debugger stdwin.fleep() def draw(self, detail): - import linecache, codehack, string + import linecache, string d = self.win.begindrawing() try: h, v = 0, 0 @@ -252,7 +252,7 @@ class Wdb(bdb.Bdb, basewin.BaseWindow): # Window debugger else: s = ' ' s = s + fn + '(' + `lineno` + ')' - s = s + codehack.getcodename(f.f_code) + s = s + f.f_code.co_name if f.f_locals.has_key('__args__'): args = f.f_locals['__args__'] if args is not None: @@ -286,6 +286,8 @@ def runcall(*args): try: apply(x.runcall, args) finally: x.close() +def set_trace(): + Wdb().set_trace() # Post-Mortem interface @@ -304,6 +306,4 @@ def pm(): TESTCMD = 'import x; x.main()' def test(): - import linecache - linecache.checkcache() run(TESTCMD) diff --git a/Lib/string.py b/Lib/string.py index afe5bec..a37cbf0 100644 --- a/Lib/string.py +++ b/Lib/string.py @@ -95,30 +95,18 @@ def joinfields(words, sep): # Find substring, raise exception if not found index_error = 'substring not found in string.index' -def index(s, sub, *args): - if args: - if len(args) > 1: - raise TypeError, 'string.index(): too many args' - i = args[0] - if i < 0: i = i + len(s) - else: - i = 0 +def index(s, sub, i = 0): + if i < 0: i = i + len(s) n = len(sub) m = len(s) + 1 - n while i < m: if sub == s[i:i+n]: return i i = i+1 - raise index_error, (s, sub) + args + raise index_error, (s, sub, i) # Find last substring, raise exception if not found -def rindex(s, sub, *args): - if args: - if len(args) > 1: - raise TypeError, 'string.rindex(): too many args' - i = args[0] - if i < 0: i = i + len(s) - else: - i = 0 +def rindex(s, sub, i = 0): + if i < 0: i = i + len(s) n = len(sub) m = len(s) + 1 - n r = None @@ -126,20 +114,35 @@ def rindex(s, sub, *args): if sub == s[i:i+n]: r = i i = i+1 if r is None: - raise index_error, (s, sub) + args + raise index_error, (s, sub, i) + return r + +# Count non-overlapping occurrences of substring +def count(s, sub, i = 0): + if i < 0: i = i + len(s) + n = len(sub) + m = len(s) + 1 - n + if n == 0: return m-i + r = 0 + while i < m: + if sub == s[i:i+n]: + r = r+1 + i = i+n + else: + i = i+1 return r # Find substring, return -1 if not found -def find(*args): +def find(s, sub, i = 0): try: - return apply(index, args) + return index(s, sub, i) except index_error: return -1 # Find last substring, return -1 if not found -def rfind(*args): +def rfind(s, sub, i = 0): try: - return apply(rindex, args) + return rindex(s, sub, i) except index_error: return -1 @@ -157,7 +160,7 @@ def atof(str): if regex.match('[0-9]*\(\.[0-9]*\)?\([eE][-+]?[0-9]+\)?', s) != len(s): raise atof_error, str try: - return eval(sign + s) + return float(eval(sign + s)) except SyntaxError: raise atof_error, str @@ -242,12 +245,36 @@ def expandtabs(s, tabsize): # it redefines some string operations that are 100-1000 times faster. # It also defines values for whitespace, lowercase and uppercase # that match <ctype.h>'s definitions. -# The manipulation with index_error is needed for compatibility. try: from strop import * letters = lowercase + uppercase +except ImportError: + pass # Use the original, slow versions + +# If certain functions are found, redefine the corresponding exceptions +# as ValueError + +try: from strop import index index_error = ValueError except ImportError: pass # Use the original, slow versions + +try: + from strop import atoi + atoi_error = ValueError +except ImportError: + pass # Use the original, slow versions + +try: + from strop import atof + atof_error = ValueError +except ImportError: + pass # Use the original, slow versions + +try: + from strop import atol + atol_error = ValueError +except ImportError: + pass # Use the original, slow versions diff --git a/Lib/stringold.py b/Lib/stringold.py index afe5bec..a37cbf0 100644 --- a/Lib/stringold.py +++ b/Lib/stringold.py @@ -95,30 +95,18 @@ def joinfields(words, sep): # Find substring, raise exception if not found index_error = 'substring not found in string.index' -def index(s, sub, *args): - if args: - if len(args) > 1: - raise TypeError, 'string.index(): too many args' - i = args[0] - if i < 0: i = i + len(s) - else: - i = 0 +def index(s, sub, i = 0): + if i < 0: i = i + len(s) n = len(sub) m = len(s) + 1 - n while i < m: if sub == s[i:i+n]: return i i = i+1 - raise index_error, (s, sub) + args + raise index_error, (s, sub, i) # Find last substring, raise exception if not found -def rindex(s, sub, *args): - if args: - if len(args) > 1: - raise TypeError, 'string.rindex(): too many args' - i = args[0] - if i < 0: i = i + len(s) - else: - i = 0 +def rindex(s, sub, i = 0): + if i < 0: i = i + len(s) n = len(sub) m = len(s) + 1 - n r = None @@ -126,20 +114,35 @@ def rindex(s, sub, *args): if sub == s[i:i+n]: r = i i = i+1 if r is None: - raise index_error, (s, sub) + args + raise index_error, (s, sub, i) + return r + +# Count non-overlapping occurrences of substring +def count(s, sub, i = 0): + if i < 0: i = i + len(s) + n = len(sub) + m = len(s) + 1 - n + if n == 0: return m-i + r = 0 + while i < m: + if sub == s[i:i+n]: + r = r+1 + i = i+n + else: + i = i+1 return r # Find substring, return -1 if not found -def find(*args): +def find(s, sub, i = 0): try: - return apply(index, args) + return index(s, sub, i) except index_error: return -1 # Find last substring, return -1 if not found -def rfind(*args): +def rfind(s, sub, i = 0): try: - return apply(rindex, args) + return rindex(s, sub, i) except index_error: return -1 @@ -157,7 +160,7 @@ def atof(str): if regex.match('[0-9]*\(\.[0-9]*\)?\([eE][-+]?[0-9]+\)?', s) != len(s): raise atof_error, str try: - return eval(sign + s) + return float(eval(sign + s)) except SyntaxError: raise atof_error, str @@ -242,12 +245,36 @@ def expandtabs(s, tabsize): # it redefines some string operations that are 100-1000 times faster. # It also defines values for whitespace, lowercase and uppercase # that match <ctype.h>'s definitions. -# The manipulation with index_error is needed for compatibility. try: from strop import * letters = lowercase + uppercase +except ImportError: + pass # Use the original, slow versions + +# If certain functions are found, redefine the corresponding exceptions +# as ValueError + +try: from strop import index index_error = ValueError except ImportError: pass # Use the original, slow versions + +try: + from strop import atoi + atoi_error = ValueError +except ImportError: + pass # Use the original, slow versions + +try: + from strop import atof + atof_error = ValueError +except ImportError: + pass # Use the original, slow versions + +try: + from strop import atol + atol_error = ValueError +except ImportError: + pass # Use the original, slow versions diff --git a/Lib/sunos4/FCNTL.py b/Lib/sunos4/FCNTL.py index 0ba5e67..1256d81 100755 --- a/Lib/sunos4/FCNTL.py +++ b/Lib/sunos4/FCNTL.py @@ -1,10 +1,10 @@ +# Generated by h2py from stdin _FOPEN = (-1) _FREAD = 0x0001 _FWRITE = 0x0002 _FNDELAY = 0x0004 _FAPPEND = 0x0008 -_FMARK = 0x0010 -_FDEFER = 0x0020 +_FSETBLK = 0x0010 _FASYNC = 0x0040 _FSHLOCK = 0x0080 _FEXLOCK = 0x0100 @@ -15,6 +15,8 @@ _FNBIO = 0x1000 _FSYNC = 0x2000 _FNONBLOCK = 0x4000 _FNOCTTY = 0x8000 +_FMARK = 0x10000 +_FDEFER = 0x20000 O_RDONLY = 0 O_WRONLY = 1 O_RDWR = 2 @@ -25,7 +27,6 @@ O_EXCL = _FEXCL O_NONBLOCK = _FNONBLOCK O_NOCTTY = _FNOCTTY O_SYNC = _FSYNC -O_ACCMODE = (O_RDONLY|O_WRONLY|O_RDWR) FAPPEND = _FAPPEND FSYNC = _FSYNC FASYNC = _FASYNC @@ -36,6 +37,7 @@ FREAD = _FREAD FWRITE = _FWRITE FMARK = _FMARK FDEFER = _FDEFER +FSETBLK = _FSETBLK FSHLOCK = _FSHLOCK FEXLOCK = _FEXLOCK FOPEN = _FOPEN @@ -62,3 +64,4 @@ F_RDLCK = 1 F_WRLCK = 2 F_UNLCK = 3 F_UNLKSYS = 4 +O_ACCMODE = (O_RDONLY|O_WRONLY|O_RDWR) diff --git a/Lib/sunos4/IN.py b/Lib/sunos4/IN.py index 05188af..a05a944 100755 --- a/Lib/sunos4/IN.py +++ b/Lib/sunos4/IN.py @@ -1,8 +1,4 @@ -# Symbolic constants from <netinet/in.h>. -# These constants are SunOS specific! (Possibly even SunOS 4.1.1) -# See demo/scripts/h2py.py for a tool to help generate a version for -# your system. - +# Generated by h2py from /usr/include/netinet/in.h IPPROTO_IP = 0 IPPROTO_ICMP = 1 IPPROTO_IGMP = 2 diff --git a/Lib/sunos4/SOCKET.py b/Lib/sunos4/SOCKET.py index c1b8542..65ce4bc 100755 --- a/Lib/sunos4/SOCKET.py +++ b/Lib/sunos4/SOCKET.py @@ -1,3 +1,4 @@ +# Generated by h2py from /usr/include/sys/socket.h SOCK_STREAM = 1 SOCK_DGRAM = 2 SOCK_RAW = 3 diff --git a/Lib/sunos4/WAIT.py b/Lib/sunos4/WAIT.py new file mode 100755 index 0000000..43612f0 --- /dev/null +++ b/Lib/sunos4/WAIT.py @@ -0,0 +1,13 @@ +# Generated by h2py from /usr/include/sys/wait.h +WUNTRACED = 0004 +WNOHANG = 0100 +WEXITED = 0001 +WTRAPPED = 0002 +WSTOPPED = WUNTRACED +WCONTINUED = 0010 +WNOWAIT = 0200 +WOPTMASK = (WEXITED|WTRAPPED|WSTOPPED|WCONTINUED|WNOHANG|WNOWAIT) +WSTOPFLG = 0177 +WCONTFLG = 0177777 +WCOREFLG = 0200 +WSIGMASK = 0177 diff --git a/Lib/sunos4/regen b/Lib/sunos4/regen index f1482db..8b52d74 100755 --- a/Lib/sunos4/regen +++ b/Lib/sunos4/regen @@ -8,4 +8,5 @@ set -v h2py </usr/include/sys/fcntlcom.h >FCNTL.py echo "O_ACCMODE = (O_RDONLY|O_WRONLY|O_RDWR)" >>FCNTL.py h2py /usr/include/sys/socket.h +h2py /usr/include/sys/wait.h h2py -i '(u_long)' /usr/include/netinet/in.h diff --git a/Lib/symbol.py b/Lib/symbol.py index 1422f12..f3ec122 100755 --- a/Lib/symbol.py +++ b/Lib/symbol.py @@ -3,49 +3,49 @@ single_input = 256 file_input = 257 eval_input = 258 -lambda_input = 259 -funcdef = 260 -parameters = 261 -varargslist = 262 -fpdef = 263 -fplist = 264 -stmt = 265 -simple_stmt = 266 -small_stmt = 267 -expr_stmt = 268 -print_stmt = 269 -del_stmt = 270 -pass_stmt = 271 -flow_stmt = 272 -break_stmt = 273 -continue_stmt = 274 -return_stmt = 275 -raise_stmt = 276 -import_stmt = 277 -global_stmt = 278 -access_stmt = 279 -accesstype = 280 -exec_stmt = 281 -compound_stmt = 282 -if_stmt = 283 -while_stmt = 284 -for_stmt = 285 -try_stmt = 286 -except_clause = 287 -suite = 288 -test = 289 -and_test = 290 -not_test = 291 -comparison = 292 -comp_op = 293 -expr = 294 -xor_expr = 295 -and_expr = 296 -shift_expr = 297 -arith_expr = 298 -term = 299 -factor = 300 -atom = 301 +funcdef = 259 +parameters = 260 +varargslist = 261 +fpdef = 262 +fplist = 263 +stmt = 264 +simple_stmt = 265 +small_stmt = 266 +expr_stmt = 267 +print_stmt = 268 +del_stmt = 269 +pass_stmt = 270 +flow_stmt = 271 +break_stmt = 272 +continue_stmt = 273 +return_stmt = 274 +raise_stmt = 275 +import_stmt = 276 +global_stmt = 277 +access_stmt = 278 +accesstype = 279 +exec_stmt = 280 +compound_stmt = 281 +if_stmt = 282 +while_stmt = 283 +for_stmt = 284 +try_stmt = 285 +except_clause = 286 +suite = 287 +test = 288 +and_test = 289 +not_test = 290 +comparison = 291 +comp_op = 292 +expr = 293 +xor_expr = 294 +and_expr = 295 +shift_expr = 296 +arith_expr = 297 +term = 298 +factor = 299 +atom = 300 +lambdef = 301 trailer = 302 subscript = 303 exprlist = 304 diff --git a/Lib/test/test_b1.py b/Lib/test/test_b1.py index 434b379..5eb4f09 100644 --- a/Lib/test/test_b1.py +++ b/Lib/test/test_b1.py @@ -97,6 +97,22 @@ if filter(None, [1, 'hello', [], [3], '', None, 9, 0]) <> [1, 'hello', [3], 9]: raise TestFailed, 'filter (remove false values)' if filter(lambda x: x > 0, [1, -3, 9, 0, 2]) <> [1, 9, 2]: raise TestFailed, 'filter (keep positives)' +class Squares: + def __init__(self, max): + self.max = max + self.sofar = [] + def __len__(self): return len(self.sofar) + def __getitem__(self, i): + if not 0 <= i < self.max: raise IndexError + n = len(self.sofar) + while n <= i: + self.sofar.append(n*n) + n = n+1 + return self.sofar[i] +if filter(None, Squares(10)) != [1, 4, 9, 16, 25, 36, 49, 64, 81]: + raise TestFailed, 'filter(None, Squares(10))' +if filter(lambda x: x%2, Squares(10)) != [1, 9, 25, 49, 81]: + raise TestFailed, 'filter(oddp, Squares(10))' print 'float' if float(3.14) <> 3.14: raise TestFailed, 'float(3.14)' @@ -158,6 +174,14 @@ if map(plus, [1, 3, 7], [4, 9, 2]) <> [1+4, 3+9, 7+2]: raise TestFailed, 'map(plus, [1, 3, 7], [4, 9, 2])' if map(plus, [1, 3, 7], [4, 9, 2], [1, 1, 0]) <> [1+4+1, 3+9+1, 7+2+0]: raise TestFailed, 'map(plus, [1, 3, 7], [4, 9, 2], [1, 1, 0])' +if map(None, Squares(10)) != [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]: + raise TestFailed, 'map(None, Squares(10))' +if map(int, Squares(10)) != [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]: + raise TestFailed, 'map(int, Squares(10))' +if map(None, Squares(3), Squares(2)) != [(0,0), (1,1), (4,None)]: + raise TestFailed, 'map(None: x, Squares(3), Squares(2))' +if map(max, Squares(3), Squares(2)) != [0, 1, 4]: + raise TestFailed, 'map(None: x, Squares(3), Squares(2))' print 'max' if max('123123') <> '3': raise TestFailed, 'max(\'123123\')' diff --git a/Lib/test/test_b2.py b/Lib/test/test_b2.py index 7118b08..10c0bfb 100644 --- a/Lib/test/test_b2.py +++ b/Lib/test/test_b2.py @@ -121,6 +121,25 @@ if reduce(lambda x, y: x*y, range(2,8), 1) <> 5040: raise TestFailed, 'reduce(): compute 7!' if reduce(lambda x, y: x*y, range(2,21), 1L) <> 2432902008176640000L: raise TestFailed, 'reduce(): compute 20!, use long' +class Squares: + def __init__(self, max): + self.max = max + self.sofar = [] + def __len__(self): return len(self.sofar) + def __getitem__(self, i): + if not 0 <= i < self.max: raise IndexError + n = len(self.sofar) + while n <= i: + self.sofar.append(n*n) + n = n+1 + return self.sofar[i] +if reduce(lambda x, y: x+y, Squares(10)) != 285: + raise TestFailed, 'reduce(<+>, Squares(10))' +if reduce(lambda x, y: x+y, Squares(10), 0) != 285: + raise TestFailed, 'reduce(<+>, Squares(10), 0)' +if reduce(lambda x, y: x+y, Squares(0), 0) != 0: + raise TestFailed, 'reduce(<+>, Squares(0), 0)' + print 'reload' import string diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index 0988574..67baf09 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -41,7 +41,7 @@ if maxint == 2147483647: raise TestFailed, \ 'No OverflowError on huge integer literal ' + `s` elif eval('maxint == 9223372036854775807'): - if eval('9223372036854775807-1 != -01000000000000000000000'): + if eval('-9223372036854775807-1 != 01000000000000000000000'): raise TestFailed, 'max negative int' if eval('01777777777777777777777') != -1: raise TestFailed, 'oct -1' if eval('0xffffffffffffffff') != -1: raise TestFailed, 'hex -1' @@ -91,9 +91,35 @@ x = '"'; y = "\""; assert(len(x) == 1 and x == y and ord(x) == 34) x = "doesn't \"shrink\" does it" y = 'doesn\'t "shrink" does it' assert(len(x) == 24 and x == y) -x = "doesn \"shrink\" doesn't it" -y = 'doesn "shrink" doesn\'t it' -assert(len(x) == 25 and x == y) +x = "does \"shrink\" doesn't it" +y = 'does "shrink" doesn\'t it' +assert(len(x) == 24 and x == y) +x = """ +The "quick" +brown fox +jumps over +the 'lazy' dog. +""" +y = '\nThe "quick"\nbrown fox\njumps over\nthe \'lazy\' dog.\n' +assert(x == y) +y = ''' +The "quick" +brown fox +jumps over +the 'lazy' dog. +'''; assert(x == y) +y = "\n\ +The \"quick\"\n\ +brown fox\n\ +jumps over\n\ +the 'lazy' dog.\n\ +"; assert(x == y) +y = '\n\ +The \"quick\"\n\ +brown fox\n\ +jumps over\n\ +the \'lazy\' dog.\n\ +'; assert(x == y) print '1.2 Grammar' @@ -113,7 +139,8 @@ x = eval('1, 0 or 1') print 'funcdef' ### 'def' NAME parameters ':' suite ### parameters: '(' [varargslist] ')' -### varargslist: (fpdef ',')* '*' NAME | fpdef (',' fpdef)* [','] +### varargslist: (fpdef ['=' test] ',')* '*' NAME +### | fpdef ['=' test] (',' fpdef ['=' test])* [','] ### fpdef: NAME | '(' fplist ')' ### fplist: fpdef (',' fpdef)* [','] def f1(): pass @@ -126,6 +153,54 @@ def v0(*rest): pass def v1(a, *rest): pass def v2(a, b, *rest): pass def v3(a, (b, c), *rest): pass +def d01(a=1): pass +d01() +d01(1) +def d11(a, b=1): pass +d11(1) +d11(1, 2) +def d21(a, b, c=1): pass +d21(1, 2) +d21(1, 2, 3) +def d02(a=1, b=2): pass +d02() +d02(1) +d02(1, 2) +def d12(a, b=1, c=2): pass +d12(1) +d12(1, 2) +d12(1, 2, 3) +def d22(a, b, c=1, d=2): pass +d22(1, 2) +d22(1, 2, 3) +d22(1, 2, 3, 4) +def d01v(a=1, *rest): pass +d01v() +d01v(1) +d01v(1, 2) +def d11v(a, b=1, *rest): pass +d11v(1) +d11v(1, 2) +d11v(1, 2, 3) +def d21v(a, b, c=1, *rest): pass +d21v(1, 2) +d21v(1, 2, 3) +d21v(1, 2, 3, 4) +def d02v(a=1, b=2, *rest): pass +d02v() +d02v(1) +d02v(1, 2) +d02v(1, 2, 3) +def d12v(a, b=1, c=2, *rest): pass +d12v(1) +d12v(1, 2) +d12v(1, 2, 3) +d12v(1, 2, 3, 4) +def d22v(a, b, c=1, d=2, *rest): pass +d22v(1, 2) +d22v(1, 2, 3) +d22v(1, 2, 3, 4) +d22v(1, 2, 3, 4, 5) ### stmt: simple_stmt | compound_stmt # Tested below @@ -184,17 +259,11 @@ try: raise KeyboardInterrupt except KeyboardInterrupt: pass print 'import_stmt' # 'import' NAME (',' NAME)* | 'from' NAME 'import' ('*' | NAME (',' NAME)*) -[1] import sys -[2] import time, math -[3] -from time import sleep -[4] +from time import time from sys import * -[5] from math import sin, cos -[6] print 'global_stmt' # 'global' NAME (',' NAME)* def f(): @@ -242,24 +311,41 @@ while 0: pass else: pass print 'for_stmt' # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] -[1] for i in 1, 2, 3: pass -[2] for i, j, k in (): pass else: pass -[3] - -print 'try_stmt' # 'try' ':' suite (except_clause ':' suite)+ | 'try' ':' suite 'finally' ':' suite +class Squares: + def __init__(self, max): + self.max = max + self.sofar = [] + def __len__(self): return len(self.sofar) + def __getitem__(self, i): + if not 0 <= i < self.max: raise IndexError + n = len(self.sofar) + while n <= i: + self.sofar.append(n*n) + n = n+1 + return self.sofar[i] +n = 0 +for x in Squares(10): n = n+x +if n != 285: raise TestFailed, 'for over growing sequence' + +print 'try_stmt' +### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] +### | 'try' ':' suite 'finally' ':' suite ### except_clause: 'except' [expr [',' expr]] try: 1/0 except ZeroDivisionError: pass +else: + pass try: 1/0 except EOFError: pass except TypeError, msg: pass except RuntimeError, msg: pass except: pass +else: pass try: 1/0 except (EOFError, TypeError, ZeroDivisionError): pass try: 1/0 diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 0a43de3..6a3f772 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -67,6 +67,10 @@ if (-12) + 24 <> 12: raise TestFailed, 'int op' if (-12) + (-24) <> -36: raise TestFailed, 'int op' if not 12 < 24: raise TestFailed, 'int op' if not -24 < -12: raise TestFailed, 'int op' +# Test for a particular bug in integer multiply +xsize, ysize, zsize = 238, 356, 4 +if not (xsize*ysize*zsize == zsize*xsize*ysize == 338912): + raise TestFailed, 'int mul commutativity' print '6.4.2 Long integers' if 12L + 24L <> 36L: raise TestFailed, 'long op' if 12L + (-24L) <> -12L: raise TestFailed, 'long op' @@ -94,6 +98,8 @@ if 0*'abcde' <> '': raise TestFailed, 'string repetition 0*' if min('abc') <> 'a' or max('abc') <> 'c': raise TestFailed, 'min/max string' if 'a' in 'abc' and 'b' in 'abc' and 'c' in 'abc' and 'd' not in 'abc': pass else: raise TestFailed, 'in/not in string' +x = 'x'*103 +if '%s!'%x != x+'!': raise TestFailed, 'nasty string formatting bug' print '6.5.2 Tuples' if len(()) <> 0: raise TestFailed, 'len(())' diff --git a/Lib/test/testall.out b/Lib/test/testall.out index 46a728e..b921512 100644 --- a/Lib/test/testall.out +++ b/Lib/test/testall.out @@ -15,8 +15,6 @@ eval_input funcdef simple_stmt expr_stmt -1 -(1, 2, 3) print_stmt 1 2 3 1 2 3 @@ -29,20 +27,11 @@ continue_stmt return_stmt raise_stmt import_stmt -[1] -[2] -[3] -[4] -[5] -[6] global_stmt exec_stmt if_stmt while_stmt for_stmt -[1] -[2] -[3] try_stmt suite test diff --git a/Lib/tzparse.py b/Lib/tzparse.py index 26824ab..ef325e9 100644 --- a/Lib/tzparse.py +++ b/Lib/tzparse.py @@ -12,7 +12,7 @@ def tzparse(tzstr): if tzprog == None: import regex tzprog = regex.compile(tzpat) - if not tzprog.match(tzstr): + if tzprog.match(tzstr) < 0: raise ValueError, 'not the TZ syntax I understand' regs = tzprog.regs subs = [] @@ -78,5 +78,3 @@ def test(): x = localtime(t) tm = x[:-1] + (0,) print 'd =', d, 't =', t, '=', asctime(tm), x[-1] - -test() diff --git a/Lib/whrandom.py b/Lib/whrandom.py index c7881b5..670ca7a 100644 --- a/Lib/whrandom.py +++ b/Lib/whrandom.py @@ -35,31 +35,25 @@ class whrandom: # Without arguments, initialize from current time. # With arguments (x, y, z), initialize from them. # - def __init__(self, *xyz): - if not xyz: + def __init__(self, x = None, y = None, z = None): + if x is None: # Initialize from current time import time t = int(time.time()) t, x = divmod(t, 256) t, y = divmod(t, 256) t, z = divmod(t, 256) - else: - # Initialize from arguments (x, y, z) - x, y, z = xyz self.seed(x, y, z) # # Set the seed from (x, y, z). # These must be integers in the range [0, 256). # - def seed(self, *xyz): - if type(xyz) <> type(()) or len(xyz) <> 3: - raise TypeError, '3 seeds required' - x, y, z = xyz + def seed(self, x, y, z): if not type(x) == type(y) == type(z) == type(0): raise TypeError, 'seeds must be integers' if not 0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256: raise ValueError, 'seeds must be in range(0, 256)' - self._seed = xyz + self._seed = (x, y, z) # # Get the next random number in the range [0.0, 1.0). # |