summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/UserList.py6
-rw-r--r--Lib/aifc.py5
-rw-r--r--Lib/audiodev.py55
-rw-r--r--Lib/bdb.py47
-rw-r--r--Lib/calendar.py7
-rw-r--r--Lib/cmd.py34
-rw-r--r--Lib/codehack.py4
-rw-r--r--Lib/dis.py4
-rw-r--r--Lib/ftplib.py113
-rwxr-xr-xLib/irix5/FCNTL.py58
-rwxr-xr-xLib/irix5/IN.py44
-rwxr-xr-xLib/irix5/SOCKET.py37
-rwxr-xr-xLib/irix5/cddb.py26
-rwxr-xr-xLib/irix5/flp.py8
-rw-r--r--Lib/lib-old/codehack.py4
-rw-r--r--Lib/lib-old/newdir.py8
-rw-r--r--Lib/lib-old/packmail.py24
-rw-r--r--Lib/lib-stdwin/WindowSched.py11
-rw-r--r--Lib/lib-stdwin/filewin.py6
-rw-r--r--Lib/lib-stdwin/wdb.py8
-rw-r--r--Lib/mimetools.py78
-rw-r--r--Lib/multifile.py11
-rw-r--r--Lib/newdir.py8
-rw-r--r--Lib/nntplib.py5
-rw-r--r--Lib/ospath.py18
-rw-r--r--Lib/packmail.py24
-rw-r--r--Lib/pdb.doc7
-rwxr-xr-xLib/pdb.py170
-rwxr-xr-xLib/plat-irix5/FCNTL.py58
-rwxr-xr-xLib/plat-irix5/IN.py44
-rwxr-xr-xLib/plat-irix5/SOCKET.py37
-rwxr-xr-xLib/plat-irix5/cddb.py26
-rwxr-xr-xLib/plat-irix5/flp.py8
-rwxr-xr-xLib/plat-sunos4/FCNTL.py9
-rwxr-xr-xLib/plat-sunos4/IN.py6
-rwxr-xr-xLib/plat-sunos4/SOCKET.py1
-rwxr-xr-xLib/plat-sunos4/WAIT.py13
-rwxr-xr-xLib/plat-sunos4/regen1
-rw-r--r--Lib/posixpath.py48
-rw-r--r--Lib/profile.doc776
-rwxr-xr-xLib/profile.py883
-rw-r--r--Lib/regexp.py8
-rw-r--r--Lib/repr.py13
-rw-r--r--Lib/rfc822.py216
-rw-r--r--Lib/sched.py11
-rwxr-xr-xLib/stdwin/WindowSched.py11
-rwxr-xr-xLib/stdwin/filewin.py6
-rwxr-xr-xLib/stdwin/wdb.py8
-rw-r--r--Lib/string.py75
-rw-r--r--Lib/stringold.py75
-rwxr-xr-xLib/sunos4/FCNTL.py9
-rwxr-xr-xLib/sunos4/IN.py6
-rwxr-xr-xLib/sunos4/SOCKET.py1
-rwxr-xr-xLib/sunos4/WAIT.py13
-rwxr-xr-xLib/sunos4/regen1
-rwxr-xr-xLib/symbol.py86
-rw-r--r--Lib/test/test_b1.py24
-rw-r--r--Lib/test/test_b2.py19
-rw-r--r--Lib/test/test_grammar.py120
-rw-r--r--Lib/test/test_types.py6
-rw-r--r--Lib/test/testall.out11
-rw-r--r--Lib/tzparse.py4
-rw-r--r--Lib/whrandom.py14
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
diff --git a/Lib/bdb.py b/Lib/bdb.py
index 6b3eab9..9b50767 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -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),
diff --git a/Lib/cmd.py b/Lib/cmd.py
index 87ddcfa..85115bb 100644
--- a/Lib/cmd.py
+++ b/Lib/cmd.py
@@ -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:
diff --git a/Lib/dis.py b/Lib/dis.py
index cd62500..846dc32 100644
--- a/Lib/dis.py
+++ b/Lib/dis.py
@@ -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.
diff --git a/Lib/pdb.py b/Lib/pdb.py
index 64451d5..a77dd29 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -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).
#