mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Whitespace normalization.
This commit is contained in:
parent
fa25a7d51f
commit
2344fae6d0
17 changed files with 3022 additions and 3024 deletions
11
Lib/netrc.py
11
Lib/netrc.py
|
@ -1,6 +1,6 @@
|
||||||
"""An object-oriented interface to .netrc files."""
|
"""An object-oriented interface to .netrc files."""
|
||||||
|
|
||||||
# Module and documentation by Eric S. Raymond, 21 Dec 1998
|
# Module and documentation by Eric S. Raymond, 21 Dec 1998
|
||||||
|
|
||||||
import os, shlex
|
import os, shlex
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ class netrc:
|
||||||
self.hosts = {}
|
self.hosts = {}
|
||||||
self.macros = {}
|
self.macros = {}
|
||||||
lexer = shlex.shlex(fp)
|
lexer = shlex.shlex(fp)
|
||||||
# Allows @ in hostnames. Not a big deal...
|
# Allows @ in hostnames. Not a big deal...
|
||||||
lexer.wordchars = lexer.wordchars + '.-@'
|
lexer.wordchars = lexer.wordchars + '.-@'
|
||||||
while 1:
|
while 1:
|
||||||
# Look for a machine, default, or macdef top-level keyword
|
# Look for a machine, default, or macdef top-level keyword
|
||||||
|
@ -23,7 +23,7 @@ class netrc:
|
||||||
entryname = lexer.get_token()
|
entryname = lexer.get_token()
|
||||||
elif tt == 'default':
|
elif tt == 'default':
|
||||||
entryname = 'default'
|
entryname = 'default'
|
||||||
elif tt == 'macdef': # Just skip to end of macdefs
|
elif tt == 'macdef': # Just skip to end of macdefs
|
||||||
entryname = lexer.get_token()
|
entryname = lexer.get_token()
|
||||||
self.macros[entryname] = []
|
self.macros[entryname] = []
|
||||||
lexer.whitepace = ' \t'
|
lexer.whitepace = ' \t'
|
||||||
|
@ -36,7 +36,7 @@ class netrc:
|
||||||
self.macros[entryname].append(line)
|
self.macros[entryname].append(line)
|
||||||
else:
|
else:
|
||||||
raise SyntaxError, "bad toplevel token %s, file %s, line %d" \
|
raise SyntaxError, "bad toplevel token %s, file %s, line %d" \
|
||||||
% (tt, file, lexer.lineno)
|
% (tt, file, lexer.lineno)
|
||||||
|
|
||||||
# We're looking at start of an entry for a named machine or default.
|
# We're looking at start of an entry for a named machine or default.
|
||||||
if toplevel == 'machine':
|
if toplevel == 'machine':
|
||||||
|
@ -87,6 +87,5 @@ class netrc:
|
||||||
rep = rep + "\n"
|
rep = rep + "\n"
|
||||||
return rep
|
return rep
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print netrc()
|
print netrc()
|
||||||
|
|
||||||
|
|
804
Lib/nntplib.py
804
Lib/nntplib.py
|
@ -34,36 +34,36 @@ import socket
|
||||||
import string
|
import string
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Exceptions raised when an error or invalid response is received
|
# Exceptions raised when an error or invalid response is received
|
||||||
class NNTPError(Exception):
|
class NNTPError(Exception):
|
||||||
"""Base class for all nntplib exceptions"""
|
"""Base class for all nntplib exceptions"""
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
apply(Exception.__init__, (self,)+args)
|
apply(Exception.__init__, (self,)+args)
|
||||||
try:
|
try:
|
||||||
self.response = args[0]
|
self.response = args[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
self.response = 'No response given'
|
self.response = 'No response given'
|
||||||
|
|
||||||
class NNTPReplyError(NNTPError):
|
class NNTPReplyError(NNTPError):
|
||||||
"""Unexpected [123]xx reply"""
|
"""Unexpected [123]xx reply"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class NNTPTemporaryError(NNTPError):
|
class NNTPTemporaryError(NNTPError):
|
||||||
"""4xx errors"""
|
"""4xx errors"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class NNTPPermanentError(NNTPError):
|
class NNTPPermanentError(NNTPError):
|
||||||
"""5xx errors"""
|
"""5xx errors"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class NNTPProtocolError(NNTPError):
|
class NNTPProtocolError(NNTPError):
|
||||||
"""Response does not begin with [1-5]"""
|
"""Response does not begin with [1-5]"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class NNTPDataError(NNTPError):
|
class NNTPDataError(NNTPError):
|
||||||
"""Error in response data"""
|
"""Error in response data"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# for backwards compatibility
|
# for backwards compatibility
|
||||||
error_reply = NNTPReplyError
|
error_reply = NNTPReplyError
|
||||||
|
@ -73,7 +73,7 @@ error_proto = NNTPProtocolError
|
||||||
error_data = NNTPDataError
|
error_data = NNTPDataError
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Standard port used by NNTP servers
|
# Standard port used by NNTP servers
|
||||||
NNTP_PORT = 119
|
NNTP_PORT = 119
|
||||||
|
|
||||||
|
@ -86,450 +86,450 @@ LONGRESP = ['100', '215', '220', '221', '222', '224', '230', '231', '282']
|
||||||
CRLF = '\r\n'
|
CRLF = '\r\n'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# The class itself
|
# The class itself
|
||||||
class NNTP:
|
class NNTP:
|
||||||
def __init__(self, host, port=NNTP_PORT, user=None, password=None,
|
def __init__(self, host, port=NNTP_PORT, user=None, password=None,
|
||||||
readermode=None):
|
readermode=None):
|
||||||
"""Initialize an instance. Arguments:
|
"""Initialize an instance. Arguments:
|
||||||
- host: hostname to connect to
|
- host: hostname to connect to
|
||||||
- port: port to connect to (default the standard NNTP port)
|
- port: port to connect to (default the standard NNTP port)
|
||||||
- user: username to authenticate with
|
- user: username to authenticate with
|
||||||
- password: password to use with username
|
- password: password to use with username
|
||||||
- readermode: if true, send 'mode reader' command after
|
- readermode: if true, send 'mode reader' command after
|
||||||
connecting.
|
connecting.
|
||||||
|
|
||||||
readermode is sometimes necessary if you are connecting to an
|
readermode is sometimes necessary if you are connecting to an
|
||||||
NNTP server on the local machine and intend to call
|
NNTP server on the local machine and intend to call
|
||||||
reader-specific comamnds, such as `group'. If you get
|
reader-specific comamnds, such as `group'. If you get
|
||||||
unexpected NNTPPermanentErrors, you might need to set
|
unexpected NNTPPermanentErrors, you might need to set
|
||||||
readermode.
|
readermode.
|
||||||
"""
|
"""
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.sock.connect((self.host, self.port))
|
self.sock.connect((self.host, self.port))
|
||||||
self.file = self.sock.makefile('rb')
|
self.file = self.sock.makefile('rb')
|
||||||
self.debugging = 0
|
self.debugging = 0
|
||||||
self.welcome = self.getresp()
|
self.welcome = self.getresp()
|
||||||
if readermode:
|
if readermode:
|
||||||
try:
|
try:
|
||||||
self.welcome = self.shortcmd('mode reader')
|
self.welcome = self.shortcmd('mode reader')
|
||||||
except NNTPPermanentError:
|
except NNTPPermanentError:
|
||||||
# error 500, probably 'not implemented'
|
# error 500, probably 'not implemented'
|
||||||
pass
|
pass
|
||||||
if user:
|
if user:
|
||||||
resp = self.shortcmd('authinfo user '+user)
|
resp = self.shortcmd('authinfo user '+user)
|
||||||
if resp[:3] == '381':
|
if resp[:3] == '381':
|
||||||
if not password:
|
if not password:
|
||||||
raise NNTPReplyError(resp)
|
raise NNTPReplyError(resp)
|
||||||
else:
|
else:
|
||||||
resp = self.shortcmd(
|
resp = self.shortcmd(
|
||||||
'authinfo pass '+password)
|
'authinfo pass '+password)
|
||||||
if resp[:3] != '281':
|
if resp[:3] != '281':
|
||||||
raise NNTPPermanentError(resp)
|
raise NNTPPermanentError(resp)
|
||||||
|
|
||||||
# Get the welcome message from the server
|
# Get the welcome message from the server
|
||||||
# (this is read and squirreled away by __init__()).
|
# (this is read and squirreled away by __init__()).
|
||||||
# If the response code is 200, posting is allowed;
|
# If the response code is 200, posting is allowed;
|
||||||
# if it 201, posting is not allowed
|
# if it 201, posting is not allowed
|
||||||
|
|
||||||
def getwelcome(self):
|
def getwelcome(self):
|
||||||
"""Get the welcome message from the server
|
"""Get the welcome message from the server
|
||||||
(this is read and squirreled away by __init__()).
|
(this is read and squirreled away by __init__()).
|
||||||
If the response code is 200, posting is allowed;
|
If the response code is 200, posting is allowed;
|
||||||
if it 201, posting is not allowed."""
|
if it 201, posting is not allowed."""
|
||||||
|
|
||||||
if self.debugging: print '*welcome*', `self.welcome`
|
if self.debugging: print '*welcome*', `self.welcome`
|
||||||
return self.welcome
|
return self.welcome
|
||||||
|
|
||||||
def set_debuglevel(self, level):
|
def set_debuglevel(self, level):
|
||||||
"""Set the debugging level. Argument 'level' means:
|
"""Set the debugging level. Argument 'level' means:
|
||||||
0: no debugging output (default)
|
0: no debugging output (default)
|
||||||
1: print commands and responses but not body text etc.
|
1: print commands and responses but not body text etc.
|
||||||
2: also print raw lines read and sent before stripping CR/LF"""
|
2: also print raw lines read and sent before stripping CR/LF"""
|
||||||
|
|
||||||
self.debugging = level
|
self.debugging = level
|
||||||
debug = set_debuglevel
|
debug = set_debuglevel
|
||||||
|
|
||||||
def putline(self, line):
|
def putline(self, line):
|
||||||
"""Internal: send one line to the server, appending CRLF."""
|
"""Internal: send one line to the server, appending CRLF."""
|
||||||
line = line + CRLF
|
line = line + CRLF
|
||||||
if self.debugging > 1: print '*put*', `line`
|
if self.debugging > 1: print '*put*', `line`
|
||||||
self.sock.send(line)
|
self.sock.send(line)
|
||||||
|
|
||||||
def putcmd(self, line):
|
def putcmd(self, line):
|
||||||
"""Internal: send one command to the server (through putline())."""
|
"""Internal: send one command to the server (through putline())."""
|
||||||
if self.debugging: print '*cmd*', `line`
|
if self.debugging: print '*cmd*', `line`
|
||||||
self.putline(line)
|
self.putline(line)
|
||||||
|
|
||||||
def getline(self):
|
def getline(self):
|
||||||
"""Internal: return one line from the server, stripping CRLF.
|
"""Internal: return one line from the server, stripping CRLF.
|
||||||
Raise EOFError if the connection is closed."""
|
Raise EOFError if the connection is closed."""
|
||||||
line = self.file.readline()
|
line = self.file.readline()
|
||||||
if self.debugging > 1:
|
if self.debugging > 1:
|
||||||
print '*get*', `line`
|
print '*get*', `line`
|
||||||
if not line: raise EOFError
|
if not line: raise EOFError
|
||||||
if line[-2:] == CRLF: line = line[:-2]
|
if line[-2:] == CRLF: line = line[:-2]
|
||||||
elif line[-1:] in CRLF: line = line[:-1]
|
elif line[-1:] in CRLF: line = line[:-1]
|
||||||
return line
|
return line
|
||||||
|
|
||||||
def getresp(self):
|
def getresp(self):
|
||||||
"""Internal: get a response from the server.
|
"""Internal: get a response from the server.
|
||||||
Raise various errors if the response indicates an error."""
|
Raise various errors if the response indicates an error."""
|
||||||
resp = self.getline()
|
resp = self.getline()
|
||||||
if self.debugging: print '*resp*', `resp`
|
if self.debugging: print '*resp*', `resp`
|
||||||
c = resp[:1]
|
c = resp[:1]
|
||||||
if c == '4':
|
if c == '4':
|
||||||
raise NNTPTemporaryError(resp)
|
raise NNTPTemporaryError(resp)
|
||||||
if c == '5':
|
if c == '5':
|
||||||
raise NNTPPermanentError(resp)
|
raise NNTPPermanentError(resp)
|
||||||
if c not in '123':
|
if c not in '123':
|
||||||
raise NNTPProtocolError(resp)
|
raise NNTPProtocolError(resp)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def getlongresp(self):
|
def getlongresp(self):
|
||||||
"""Internal: get a response plus following text from the server.
|
"""Internal: get a response plus following text from the server.
|
||||||
Raise various errors if the response indicates an error."""
|
Raise various errors if the response indicates an error."""
|
||||||
resp = self.getresp()
|
resp = self.getresp()
|
||||||
if resp[:3] not in LONGRESP:
|
if resp[:3] not in LONGRESP:
|
||||||
raise NNTPReplyError(resp)
|
raise NNTPReplyError(resp)
|
||||||
list = []
|
list = []
|
||||||
while 1:
|
while 1:
|
||||||
line = self.getline()
|
line = self.getline()
|
||||||
if line == '.':
|
if line == '.':
|
||||||
break
|
break
|
||||||
if line[:2] == '..':
|
if line[:2] == '..':
|
||||||
line = line[1:]
|
line = line[1:]
|
||||||
list.append(line)
|
list.append(line)
|
||||||
return resp, list
|
return resp, list
|
||||||
|
|
||||||
def shortcmd(self, line):
|
def shortcmd(self, line):
|
||||||
"""Internal: send a command and get the response."""
|
"""Internal: send a command and get the response."""
|
||||||
self.putcmd(line)
|
self.putcmd(line)
|
||||||
return self.getresp()
|
return self.getresp()
|
||||||
|
|
||||||
def longcmd(self, line):
|
def longcmd(self, line):
|
||||||
"""Internal: send a command and get the response plus following text."""
|
"""Internal: send a command and get the response plus following text."""
|
||||||
self.putcmd(line)
|
self.putcmd(line)
|
||||||
return self.getlongresp()
|
return self.getlongresp()
|
||||||
|
|
||||||
def newgroups(self, date, time):
|
def newgroups(self, date, time):
|
||||||
"""Process a NEWGROUPS command. Arguments:
|
"""Process a NEWGROUPS command. Arguments:
|
||||||
- date: string 'yymmdd' indicating the date
|
- date: string 'yymmdd' indicating the date
|
||||||
- time: string 'hhmmss' indicating the time
|
- time: string 'hhmmss' indicating the time
|
||||||
Return:
|
Return:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- list: list of newsgroup names"""
|
- list: list of newsgroup names"""
|
||||||
|
|
||||||
return self.longcmd('NEWGROUPS ' + date + ' ' + time)
|
return self.longcmd('NEWGROUPS ' + date + ' ' + time)
|
||||||
|
|
||||||
def newnews(self, group, date, time):
|
def newnews(self, group, date, time):
|
||||||
"""Process a NEWNEWS command. Arguments:
|
"""Process a NEWNEWS command. Arguments:
|
||||||
- group: group name or '*'
|
- group: group name or '*'
|
||||||
- date: string 'yymmdd' indicating the date
|
- date: string 'yymmdd' indicating the date
|
||||||
- time: string 'hhmmss' indicating the time
|
- time: string 'hhmmss' indicating the time
|
||||||
Return:
|
Return:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- list: list of article ids"""
|
- list: list of article ids"""
|
||||||
|
|
||||||
cmd = 'NEWNEWS ' + group + ' ' + date + ' ' + time
|
cmd = 'NEWNEWS ' + group + ' ' + date + ' ' + time
|
||||||
return self.longcmd(cmd)
|
return self.longcmd(cmd)
|
||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
"""Process a LIST command. Return:
|
"""Process a LIST command. Return:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- list: list of (group, last, first, flag) (strings)"""
|
- list: list of (group, last, first, flag) (strings)"""
|
||||||
|
|
||||||
resp, list = self.longcmd('LIST')
|
resp, list = self.longcmd('LIST')
|
||||||
for i in range(len(list)):
|
for i in range(len(list)):
|
||||||
# Parse lines into "group last first flag"
|
# Parse lines into "group last first flag"
|
||||||
list[i] = tuple(string.split(list[i]))
|
list[i] = tuple(string.split(list[i]))
|
||||||
return resp, list
|
return resp, list
|
||||||
|
|
||||||
def group(self, name):
|
def group(self, name):
|
||||||
"""Process a GROUP command. Argument:
|
"""Process a GROUP command. Argument:
|
||||||
- group: the group name
|
- group: the group name
|
||||||
Returns:
|
Returns:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- count: number of articles (string)
|
- count: number of articles (string)
|
||||||
- first: first article number (string)
|
- first: first article number (string)
|
||||||
- last: last article number (string)
|
- last: last article number (string)
|
||||||
- name: the group name"""
|
- name: the group name"""
|
||||||
|
|
||||||
resp = self.shortcmd('GROUP ' + name)
|
resp = self.shortcmd('GROUP ' + name)
|
||||||
if resp[:3] != '211':
|
if resp[:3] != '211':
|
||||||
raise NNTPReplyError(resp)
|
raise NNTPReplyError(resp)
|
||||||
words = string.split(resp)
|
words = string.split(resp)
|
||||||
count = first = last = 0
|
count = first = last = 0
|
||||||
n = len(words)
|
n = len(words)
|
||||||
if n > 1:
|
if n > 1:
|
||||||
count = words[1]
|
count = words[1]
|
||||||
if n > 2:
|
if n > 2:
|
||||||
first = words[2]
|
first = words[2]
|
||||||
if n > 3:
|
if n > 3:
|
||||||
last = words[3]
|
last = words[3]
|
||||||
if n > 4:
|
if n > 4:
|
||||||
name = string.lower(words[4])
|
name = string.lower(words[4])
|
||||||
return resp, count, first, last, name
|
return resp, count, first, last, name
|
||||||
|
|
||||||
def help(self):
|
def help(self):
|
||||||
"""Process a HELP command. Returns:
|
"""Process a HELP command. Returns:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- list: list of strings"""
|
- list: list of strings"""
|
||||||
|
|
||||||
return self.longcmd('HELP')
|
return self.longcmd('HELP')
|
||||||
|
|
||||||
def statparse(self, resp):
|
def statparse(self, resp):
|
||||||
"""Internal: parse the response of a STAT, NEXT or LAST command."""
|
"""Internal: parse the response of a STAT, NEXT or LAST command."""
|
||||||
if resp[:2] != '22':
|
if resp[:2] != '22':
|
||||||
raise NNTPReplyError(resp)
|
raise NNTPReplyError(resp)
|
||||||
words = string.split(resp)
|
words = string.split(resp)
|
||||||
nr = 0
|
nr = 0
|
||||||
id = ''
|
id = ''
|
||||||
n = len(words)
|
n = len(words)
|
||||||
if n > 1:
|
if n > 1:
|
||||||
nr = words[1]
|
nr = words[1]
|
||||||
if n > 2:
|
if n > 2:
|
||||||
id = words[2]
|
id = words[2]
|
||||||
return resp, nr, id
|
return resp, nr, id
|
||||||
|
|
||||||
def statcmd(self, line):
|
def statcmd(self, line):
|
||||||
"""Internal: process a STAT, NEXT or LAST command."""
|
"""Internal: process a STAT, NEXT or LAST command."""
|
||||||
resp = self.shortcmd(line)
|
resp = self.shortcmd(line)
|
||||||
return self.statparse(resp)
|
return self.statparse(resp)
|
||||||
|
|
||||||
def stat(self, id):
|
def stat(self, id):
|
||||||
"""Process a STAT command. Argument:
|
"""Process a STAT command. Argument:
|
||||||
- id: article number or message id
|
- id: article number or message id
|
||||||
Returns:
|
Returns:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- nr: the article number
|
- nr: the article number
|
||||||
- id: the article id"""
|
- id: the article id"""
|
||||||
|
|
||||||
return self.statcmd('STAT ' + id)
|
return self.statcmd('STAT ' + id)
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
"""Process a NEXT command. No arguments. Return as for STAT."""
|
"""Process a NEXT command. No arguments. Return as for STAT."""
|
||||||
return self.statcmd('NEXT')
|
return self.statcmd('NEXT')
|
||||||
|
|
||||||
def last(self):
|
def last(self):
|
||||||
"""Process a LAST command. No arguments. Return as for STAT."""
|
"""Process a LAST command. No arguments. Return as for STAT."""
|
||||||
return self.statcmd('LAST')
|
return self.statcmd('LAST')
|
||||||
|
|
||||||
def artcmd(self, line):
|
def artcmd(self, line):
|
||||||
"""Internal: process a HEAD, BODY or ARTICLE command."""
|
"""Internal: process a HEAD, BODY or ARTICLE command."""
|
||||||
resp, list = self.longcmd(line)
|
resp, list = self.longcmd(line)
|
||||||
resp, nr, id = self.statparse(resp)
|
resp, nr, id = self.statparse(resp)
|
||||||
return resp, nr, id, list
|
return resp, nr, id, list
|
||||||
|
|
||||||
def head(self, id):
|
def head(self, id):
|
||||||
"""Process a HEAD command. Argument:
|
"""Process a HEAD command. Argument:
|
||||||
- id: article number or message id
|
- id: article number or message id
|
||||||
Returns:
|
Returns:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- nr: article number
|
- nr: article number
|
||||||
- id: message id
|
- id: message id
|
||||||
- list: the lines of the article's header"""
|
- list: the lines of the article's header"""
|
||||||
|
|
||||||
return self.artcmd('HEAD ' + id)
|
return self.artcmd('HEAD ' + id)
|
||||||
|
|
||||||
def body(self, id):
|
def body(self, id):
|
||||||
"""Process a BODY command. Argument:
|
"""Process a BODY command. Argument:
|
||||||
- id: article number or message id
|
- id: article number or message id
|
||||||
Returns:
|
Returns:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- nr: article number
|
- nr: article number
|
||||||
- id: message id
|
- id: message id
|
||||||
- list: the lines of the article's body"""
|
- list: the lines of the article's body"""
|
||||||
|
|
||||||
return self.artcmd('BODY ' + id)
|
return self.artcmd('BODY ' + id)
|
||||||
|
|
||||||
def article(self, id):
|
def article(self, id):
|
||||||
"""Process an ARTICLE command. Argument:
|
"""Process an ARTICLE command. Argument:
|
||||||
- id: article number or message id
|
- id: article number or message id
|
||||||
Returns:
|
Returns:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- nr: article number
|
- nr: article number
|
||||||
- id: message id
|
- id: message id
|
||||||
- list: the lines of the article"""
|
- list: the lines of the article"""
|
||||||
|
|
||||||
return self.artcmd('ARTICLE ' + id)
|
return self.artcmd('ARTICLE ' + id)
|
||||||
|
|
||||||
def slave(self):
|
def slave(self):
|
||||||
"""Process a SLAVE command. Returns:
|
"""Process a SLAVE command. Returns:
|
||||||
- resp: server response if successful"""
|
- resp: server response if successful"""
|
||||||
|
|
||||||
return self.shortcmd('SLAVE')
|
return self.shortcmd('SLAVE')
|
||||||
|
|
||||||
def xhdr(self, hdr, str):
|
def xhdr(self, hdr, str):
|
||||||
"""Process an XHDR command (optional server extension). Arguments:
|
"""Process an XHDR command (optional server extension). Arguments:
|
||||||
- hdr: the header type (e.g. 'subject')
|
- hdr: the header type (e.g. 'subject')
|
||||||
- str: an article nr, a message id, or a range nr1-nr2
|
- str: an article nr, a message id, or a range nr1-nr2
|
||||||
Returns:
|
Returns:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- list: list of (nr, value) strings"""
|
- list: list of (nr, value) strings"""
|
||||||
|
|
||||||
pat = re.compile('^([0-9]+) ?(.*)\n?')
|
pat = re.compile('^([0-9]+) ?(.*)\n?')
|
||||||
resp, lines = self.longcmd('XHDR ' + hdr + ' ' + str)
|
resp, lines = self.longcmd('XHDR ' + hdr + ' ' + str)
|
||||||
for i in range(len(lines)):
|
for i in range(len(lines)):
|
||||||
line = lines[i]
|
line = lines[i]
|
||||||
m = pat.match(line)
|
m = pat.match(line)
|
||||||
if m:
|
if m:
|
||||||
lines[i] = m.group(1, 2)
|
lines[i] = m.group(1, 2)
|
||||||
return resp, lines
|
return resp, lines
|
||||||
|
|
||||||
def xover(self,start,end):
|
def xover(self,start,end):
|
||||||
"""Process an XOVER command (optional server extension) Arguments:
|
"""Process an XOVER command (optional server extension) Arguments:
|
||||||
- start: start of range
|
- start: start of range
|
||||||
- end: end of range
|
- end: end of range
|
||||||
Returns:
|
Returns:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- list: list of (art-nr, subject, poster, date,
|
- list: list of (art-nr, subject, poster, date,
|
||||||
id, references, size, lines)"""
|
id, references, size, lines)"""
|
||||||
|
|
||||||
resp, lines = self.longcmd('XOVER ' + start + '-' + end)
|
resp, lines = self.longcmd('XOVER ' + start + '-' + end)
|
||||||
xover_lines = []
|
xover_lines = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
elem = string.splitfields(line,"\t")
|
elem = string.splitfields(line,"\t")
|
||||||
try:
|
try:
|
||||||
xover_lines.append((elem[0],
|
xover_lines.append((elem[0],
|
||||||
elem[1],
|
elem[1],
|
||||||
elem[2],
|
elem[2],
|
||||||
elem[3],
|
elem[3],
|
||||||
elem[4],
|
elem[4],
|
||||||
string.split(elem[5]),
|
string.split(elem[5]),
|
||||||
elem[6],
|
elem[6],
|
||||||
elem[7]))
|
elem[7]))
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise NNTPDataError(line)
|
raise NNTPDataError(line)
|
||||||
return resp,xover_lines
|
return resp,xover_lines
|
||||||
|
|
||||||
def xgtitle(self, group):
|
def xgtitle(self, group):
|
||||||
"""Process an XGTITLE command (optional server extension) Arguments:
|
"""Process an XGTITLE command (optional server extension) Arguments:
|
||||||
- group: group name wildcard (i.e. news.*)
|
- group: group name wildcard (i.e. news.*)
|
||||||
Returns:
|
Returns:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
- list: list of (name,title) strings"""
|
- list: list of (name,title) strings"""
|
||||||
|
|
||||||
line_pat = re.compile("^([^ \t]+)[ \t]+(.*)$")
|
line_pat = re.compile("^([^ \t]+)[ \t]+(.*)$")
|
||||||
resp, raw_lines = self.longcmd('XGTITLE ' + group)
|
resp, raw_lines = self.longcmd('XGTITLE ' + group)
|
||||||
lines = []
|
lines = []
|
||||||
for raw_line in raw_lines:
|
for raw_line in raw_lines:
|
||||||
match = line_pat.search(string.strip(raw_line))
|
match = line_pat.search(string.strip(raw_line))
|
||||||
if match:
|
if match:
|
||||||
lines.append(match.group(1, 2))
|
lines.append(match.group(1, 2))
|
||||||
return resp, lines
|
return resp, lines
|
||||||
|
|
||||||
def xpath(self,id):
|
def xpath(self,id):
|
||||||
"""Process an XPATH command (optional server extension) Arguments:
|
"""Process an XPATH command (optional server extension) Arguments:
|
||||||
- id: Message id of article
|
- id: Message id of article
|
||||||
Returns:
|
Returns:
|
||||||
resp: server response if successful
|
resp: server response if successful
|
||||||
path: directory path to article"""
|
path: directory path to article"""
|
||||||
|
|
||||||
resp = self.shortcmd("XPATH " + id)
|
resp = self.shortcmd("XPATH " + id)
|
||||||
if resp[:3] != '223':
|
if resp[:3] != '223':
|
||||||
raise NNTPReplyError(resp)
|
raise NNTPReplyError(resp)
|
||||||
try:
|
try:
|
||||||
[resp_num, path] = string.split(resp)
|
[resp_num, path] = string.split(resp)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise NNTPReplyError(resp)
|
raise NNTPReplyError(resp)
|
||||||
else:
|
else:
|
||||||
return resp, path
|
return resp, path
|
||||||
|
|
||||||
def date (self):
|
def date (self):
|
||||||
"""Process the DATE command. Arguments:
|
"""Process the DATE command. Arguments:
|
||||||
None
|
None
|
||||||
Returns:
|
Returns:
|
||||||
resp: server response if successful
|
resp: server response if successful
|
||||||
date: Date suitable for newnews/newgroups commands etc.
|
date: Date suitable for newnews/newgroups commands etc.
|
||||||
time: Time suitable for newnews/newgroups commands etc."""
|
time: Time suitable for newnews/newgroups commands etc."""
|
||||||
|
|
||||||
resp = self.shortcmd("DATE")
|
resp = self.shortcmd("DATE")
|
||||||
if resp[:3] != '111':
|
if resp[:3] != '111':
|
||||||
raise NNTPReplyError(resp)
|
raise NNTPReplyError(resp)
|
||||||
elem = string.split(resp)
|
elem = string.split(resp)
|
||||||
if len(elem) != 2:
|
if len(elem) != 2:
|
||||||
raise NNTPDataError(resp)
|
raise NNTPDataError(resp)
|
||||||
date = elem[1][2:8]
|
date = elem[1][2:8]
|
||||||
time = elem[1][-6:]
|
time = elem[1][-6:]
|
||||||
if len(date) != 6 or len(time) != 6:
|
if len(date) != 6 or len(time) != 6:
|
||||||
raise NNTPDataError(resp)
|
raise NNTPDataError(resp)
|
||||||
return resp, date, time
|
return resp, date, time
|
||||||
|
|
||||||
|
|
||||||
def post(self, f):
|
def post(self, f):
|
||||||
"""Process a POST command. Arguments:
|
"""Process a POST command. Arguments:
|
||||||
- f: file containing the article
|
- f: file containing the article
|
||||||
Returns:
|
Returns:
|
||||||
- resp: server response if successful"""
|
- resp: server response if successful"""
|
||||||
|
|
||||||
resp = self.shortcmd('POST')
|
resp = self.shortcmd('POST')
|
||||||
# Raises error_??? if posting is not allowed
|
# Raises error_??? if posting is not allowed
|
||||||
if resp[0] != '3':
|
if resp[0] != '3':
|
||||||
raise NNTPReplyError(resp)
|
raise NNTPReplyError(resp)
|
||||||
while 1:
|
while 1:
|
||||||
line = f.readline()
|
line = f.readline()
|
||||||
if not line:
|
if not line:
|
||||||
break
|
break
|
||||||
if line[-1] == '\n':
|
if line[-1] == '\n':
|
||||||
line = line[:-1]
|
line = line[:-1]
|
||||||
if line[:1] == '.':
|
if line[:1] == '.':
|
||||||
line = '.' + line
|
line = '.' + line
|
||||||
self.putline(line)
|
self.putline(line)
|
||||||
self.putline('.')
|
self.putline('.')
|
||||||
return self.getresp()
|
return self.getresp()
|
||||||
|
|
||||||
def ihave(self, id, f):
|
def ihave(self, id, f):
|
||||||
"""Process an IHAVE command. Arguments:
|
"""Process an IHAVE command. Arguments:
|
||||||
- id: message-id of the article
|
- id: message-id of the article
|
||||||
- f: file containing the article
|
- f: file containing the article
|
||||||
Returns:
|
Returns:
|
||||||
- resp: server response if successful
|
- resp: server response if successful
|
||||||
Note that if the server refuses the article an exception is raised."""
|
Note that if the server refuses the article an exception is raised."""
|
||||||
|
|
||||||
resp = self.shortcmd('IHAVE ' + id)
|
resp = self.shortcmd('IHAVE ' + id)
|
||||||
# Raises error_??? if the server already has it
|
# Raises error_??? if the server already has it
|
||||||
if resp[0] != '3':
|
if resp[0] != '3':
|
||||||
raise NNTPReplyError(resp)
|
raise NNTPReplyError(resp)
|
||||||
while 1:
|
while 1:
|
||||||
line = f.readline()
|
line = f.readline()
|
||||||
if not line:
|
if not line:
|
||||||
break
|
break
|
||||||
if line[-1] == '\n':
|
if line[-1] == '\n':
|
||||||
line = line[:-1]
|
line = line[:-1]
|
||||||
if line[:1] == '.':
|
if line[:1] == '.':
|
||||||
line = '.' + line
|
line = '.' + line
|
||||||
self.putline(line)
|
self.putline(line)
|
||||||
self.putline('.')
|
self.putline('.')
|
||||||
return self.getresp()
|
return self.getresp()
|
||||||
|
|
||||||
def quit(self):
|
def quit(self):
|
||||||
"""Process a QUIT command and close the socket. Returns:
|
"""Process a QUIT command and close the socket. Returns:
|
||||||
- resp: server response if successful"""
|
- resp: server response if successful"""
|
||||||
|
|
||||||
resp = self.shortcmd('QUIT')
|
resp = self.shortcmd('QUIT')
|
||||||
self.file.close()
|
self.file.close()
|
||||||
self.sock.close()
|
self.sock.close()
|
||||||
del self.file, self.sock
|
del self.file, self.sock
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
def _test():
|
def _test():
|
||||||
"""Minimal test function."""
|
"""Minimal test function."""
|
||||||
s = NNTP('news', readermode='reader')
|
s = NNTP('news', readermode='reader')
|
||||||
resp, count, first, last, name = s.group('comp.lang.python')
|
resp, count, first, last, name = s.group('comp.lang.python')
|
||||||
print resp
|
print resp
|
||||||
print 'Group', name, 'has', count, 'articles, range', first, 'to', last
|
print 'Group', name, 'has', count, 'articles, range', first, 'to', last
|
||||||
resp, subs = s.xhdr('subject', first + '-' + last)
|
resp, subs = s.xhdr('subject', first + '-' + last)
|
||||||
print resp
|
print resp
|
||||||
for item in subs:
|
for item in subs:
|
||||||
print "%7s %s" % item
|
print "%7s %s" % item
|
||||||
resp = s.quit()
|
resp = s.quit()
|
||||||
print resp
|
print resp
|
||||||
|
|
||||||
|
|
||||||
# Run the test when run as a script
|
# Run the test when run as a script
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
_test()
|
_test()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Module 'ntpath' -- common operations on WinNT/Win95 pathnames
|
# Module 'ntpath' -- common operations on WinNT/Win95 pathnames
|
||||||
"""Common pathname manipulations, WindowsNT/95 version.
|
"""Common pathname manipulations, WindowsNT/95 version.
|
||||||
|
|
||||||
Instead of importing this module directly, import os and refer to this
|
Instead of importing this module directly, import os and refer to this
|
||||||
module as os.path.
|
module as os.path.
|
||||||
|
@ -254,7 +254,7 @@ def ismount(path):
|
||||||
def walk(top, func, arg):
|
def walk(top, func, arg):
|
||||||
"""Directory tree walk whth callback function.
|
"""Directory tree walk whth callback function.
|
||||||
|
|
||||||
walk(top, func, arg) calls func(arg, d, files) for each directory d
|
walk(top, func, arg) calls func(arg, d, files) for each directory d
|
||||||
in the tree rooted at top (including top itself); files is a list
|
in the tree rooted at top (including top itself); files is a list
|
||||||
of all the files and subdirs in directory d."""
|
of all the files and subdirs in directory d."""
|
||||||
try:
|
try:
|
||||||
|
@ -313,7 +313,7 @@ def expanduser(path):
|
||||||
# XXX With COMMAND.COM you can use any characters in a variable name,
|
# XXX With COMMAND.COM you can use any characters in a variable name,
|
||||||
# XXX except '^|<>='.
|
# XXX except '^|<>='.
|
||||||
|
|
||||||
def expandvars(path):
|
def expandvars(path):
|
||||||
"""Expand shell variables of form $var and ${var}.
|
"""Expand shell variables of form $var and ${var}.
|
||||||
|
|
||||||
Unknown variables are left unchanged."""
|
Unknown variables are left unchanged."""
|
||||||
|
|
|
@ -1,66 +1,66 @@
|
||||||
"""Convert a NT pathname to a file URL and vice versa."""
|
"""Convert a NT pathname to a file URL and vice versa."""
|
||||||
|
|
||||||
def url2pathname(url):
|
def url2pathname(url):
|
||||||
r"""Convert a URL to a DOS path.
|
r"""Convert a URL to a DOS path.
|
||||||
|
|
||||||
///C|/foo/bar/spam.foo
|
///C|/foo/bar/spam.foo
|
||||||
|
|
||||||
becomes
|
becomes
|
||||||
|
|
||||||
C:\foo\bar\spam.foo
|
C:\foo\bar\spam.foo
|
||||||
"""
|
"""
|
||||||
import string, urllib
|
import string, urllib
|
||||||
if not '|' in url:
|
if not '|' in url:
|
||||||
# No drive specifier, just convert slashes
|
# No drive specifier, just convert slashes
|
||||||
if url[:4] == '////':
|
if url[:4] == '////':
|
||||||
# path is something like ////host/path/on/remote/host
|
# path is something like ////host/path/on/remote/host
|
||||||
# convert this to \\host\path\on\remote\host
|
# convert this to \\host\path\on\remote\host
|
||||||
# (notice halving of slashes at the start of the path)
|
# (notice halving of slashes at the start of the path)
|
||||||
url = url[2:]
|
url = url[2:]
|
||||||
components = string.split(url, '/')
|
components = string.split(url, '/')
|
||||||
# make sure not to convert quoted slashes :-)
|
# make sure not to convert quoted slashes :-)
|
||||||
return urllib.unquote(string.join(components, '\\'))
|
return urllib.unquote(string.join(components, '\\'))
|
||||||
comp = string.split(url, '|')
|
comp = string.split(url, '|')
|
||||||
if len(comp) != 2 or comp[0][-1] not in string.letters:
|
if len(comp) != 2 or comp[0][-1] not in string.letters:
|
||||||
error = 'Bad URL: ' + url
|
error = 'Bad URL: ' + url
|
||||||
raise IOError, error
|
raise IOError, error
|
||||||
drive = string.upper(comp[0][-1])
|
drive = string.upper(comp[0][-1])
|
||||||
components = string.split(comp[1], '/')
|
components = string.split(comp[1], '/')
|
||||||
path = drive + ':'
|
path = drive + ':'
|
||||||
for comp in components:
|
for comp in components:
|
||||||
if comp:
|
if comp:
|
||||||
path = path + '\\' + urllib.unquote(comp)
|
path = path + '\\' + urllib.unquote(comp)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def pathname2url(p):
|
def pathname2url(p):
|
||||||
r"""Convert a DOS path name to a file url.
|
r"""Convert a DOS path name to a file url.
|
||||||
|
|
||||||
C:\foo\bar\spam.foo
|
C:\foo\bar\spam.foo
|
||||||
|
|
||||||
becomes
|
becomes
|
||||||
|
|
||||||
///C|/foo/bar/spam.foo
|
///C|/foo/bar/spam.foo
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import string, urllib
|
import string, urllib
|
||||||
if not ':' in p:
|
if not ':' in p:
|
||||||
# No drive specifier, just convert slashes and quote the name
|
# No drive specifier, just convert slashes and quote the name
|
||||||
if p[:2] == '\\\\':
|
if p[:2] == '\\\\':
|
||||||
# path is something like \\host\path\on\remote\host
|
# path is something like \\host\path\on\remote\host
|
||||||
# convert this to ////host/path/on/remote/host
|
# convert this to ////host/path/on/remote/host
|
||||||
# (notice doubling of slashes at the start of the path)
|
# (notice doubling of slashes at the start of the path)
|
||||||
p = '\\\\' + p
|
p = '\\\\' + p
|
||||||
components = string.split(p, '\\')
|
components = string.split(p, '\\')
|
||||||
return urllib.quote(string.join(components, '/'))
|
return urllib.quote(string.join(components, '/'))
|
||||||
comp = string.split(p, ':')
|
comp = string.split(p, ':')
|
||||||
if len(comp) != 2 or len(comp[0]) > 1:
|
if len(comp) != 2 or len(comp[0]) > 1:
|
||||||
error = 'Bad path: ' + p
|
error = 'Bad path: ' + p
|
||||||
raise IOError, error
|
raise IOError, error
|
||||||
|
|
||||||
drive = urllib.quote(string.upper(comp[0]))
|
drive = urllib.quote(string.upper(comp[0]))
|
||||||
components = string.split(comp[1], '\\')
|
components = string.split(comp[1], '\\')
|
||||||
path = '///' + drive + '|'
|
path = '///' + drive + '|'
|
||||||
for comp in components:
|
for comp in components:
|
||||||
if comp:
|
if comp:
|
||||||
path = path + '/' + urllib.quote(comp)
|
path = path + '/' + urllib.quote(comp)
|
||||||
return path
|
return path
|
||||||
|
|
|
@ -213,7 +213,7 @@ def execlpe(file, *args):
|
||||||
|
|
||||||
Execute the executable file (which is searched for along $PATH)
|
Execute the executable file (which is searched for along $PATH)
|
||||||
with argument list args and environment env, replacing the current
|
with argument list args and environment env, replacing the current
|
||||||
process. """
|
process. """
|
||||||
env = args[-1]
|
env = args[-1]
|
||||||
execvpe(file, args[:-1], env)
|
execvpe(file, args[:-1], env)
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ def execvpe(file, args, env):
|
||||||
Execute the executable file (which is searched for along $PATH)
|
Execute the executable file (which is searched for along $PATH)
|
||||||
with argument list args and environment env , replacing the
|
with argument list args and environment env , replacing the
|
||||||
current process.
|
current process.
|
||||||
args may be a list or tuple of strings. """
|
args may be a list or tuple of strings. """
|
||||||
_execvpe(file, args, env)
|
_execvpe(file, args, env)
|
||||||
|
|
||||||
_notfound = None
|
_notfound = None
|
||||||
|
@ -370,7 +370,7 @@ if _exists("fork") and not _exists("spawnv") and _exists("execv"):
|
||||||
Execute file with arguments from args in a subprocess.
|
Execute file with arguments from args in a subprocess.
|
||||||
If mode == P_NOWAIT return the pid of the process.
|
If mode == P_NOWAIT return the pid of the process.
|
||||||
If mode == P_WAIT return the process's exit code if it exits normally;
|
If mode == P_WAIT return the process's exit code if it exits normally;
|
||||||
otherwise return -SIG, where SIG is the signal that killed it. """
|
otherwise return -SIG, where SIG is the signal that killed it. """
|
||||||
return _spawnvef(mode, file, args, None, execv)
|
return _spawnvef(mode, file, args, None, execv)
|
||||||
|
|
||||||
def spawnve(mode, file, args, env):
|
def spawnve(mode, file, args, env):
|
||||||
|
|
1766
Lib/pdb.py
1766
Lib/pdb.py
File diff suppressed because it is too large
Load diff
|
@ -123,7 +123,7 @@ class Pickler:
|
||||||
return LONG_BINGET + s
|
return LONG_BINGET + s
|
||||||
|
|
||||||
return GET + `i` + '\n'
|
return GET + `i` + '\n'
|
||||||
|
|
||||||
def save(self, object, pers_save = 0):
|
def save(self, object, pers_save = 0):
|
||||||
memo = self.memo
|
memo = self.memo
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ class Pickler:
|
||||||
return
|
return
|
||||||
|
|
||||||
d = id(object)
|
d = id(object)
|
||||||
|
|
||||||
t = type(object)
|
t = type(object)
|
||||||
|
|
||||||
if ((t is TupleType) and (len(object) == 0)):
|
if ((t is TupleType) and (len(object) == 0)):
|
||||||
|
@ -179,14 +179,14 @@ class Pickler:
|
||||||
"tuple" % reduce
|
"tuple" % reduce
|
||||||
|
|
||||||
l = len(tup)
|
l = len(tup)
|
||||||
|
|
||||||
if ((l != 2) and (l != 3)):
|
if ((l != 2) and (l != 3)):
|
||||||
raise PicklingError, "tuple returned by %s must contain " \
|
raise PicklingError, "tuple returned by %s must contain " \
|
||||||
"only two or three elements" % reduce
|
"only two or three elements" % reduce
|
||||||
|
|
||||||
callable = tup[0]
|
callable = tup[0]
|
||||||
arg_tup = tup[1]
|
arg_tup = tup[1]
|
||||||
|
|
||||||
if (l > 2):
|
if (l > 2):
|
||||||
state = tup[2]
|
state = tup[2]
|
||||||
else:
|
else:
|
||||||
|
@ -196,7 +196,7 @@ class Pickler:
|
||||||
raise PicklingError, "Second element of tuple returned " \
|
raise PicklingError, "Second element of tuple returned " \
|
||||||
"by %s must be a tuple" % reduce
|
"by %s must be a tuple" % reduce
|
||||||
|
|
||||||
self.save_reduce(callable, arg_tup, state)
|
self.save_reduce(callable, arg_tup, state)
|
||||||
memo_len = len(memo)
|
memo_len = len(memo)
|
||||||
self.write(self.put(memo_len))
|
self.write(self.put(memo_len))
|
||||||
memo[d] = (memo_len, object)
|
memo[d] = (memo_len, object)
|
||||||
|
@ -224,7 +224,7 @@ class Pickler:
|
||||||
save(callable)
|
save(callable)
|
||||||
save(arg_tup)
|
save(arg_tup)
|
||||||
write(REDUCE)
|
write(REDUCE)
|
||||||
|
|
||||||
if (state is not None):
|
if (state is not None):
|
||||||
save(state)
|
save(state)
|
||||||
write(BUILD)
|
write(BUILD)
|
||||||
|
@ -317,7 +317,7 @@ class Pickler:
|
||||||
if (self.bin):
|
if (self.bin):
|
||||||
write(POP_MARK + self.get(memo[d][0]))
|
write(POP_MARK + self.get(memo[d][0]))
|
||||||
return
|
return
|
||||||
|
|
||||||
write(POP * (len(object) + 1) + self.get(memo[d][0]))
|
write(POP * (len(object) + 1) + self.get(memo[d][0]))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ class Pickler:
|
||||||
|
|
||||||
for element in object:
|
for element in object:
|
||||||
save(element)
|
save(element)
|
||||||
|
|
||||||
if (not using_appends):
|
if (not using_appends):
|
||||||
write(APPEND)
|
write(APPEND)
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@ class Unpickler:
|
||||||
|
|
||||||
def load_binpersid(self):
|
def load_binpersid(self):
|
||||||
stack = self.stack
|
stack = self.stack
|
||||||
|
|
||||||
pid = stack[-1]
|
pid = stack[-1]
|
||||||
del stack[-1]
|
del stack[-1]
|
||||||
|
|
||||||
|
@ -568,7 +568,7 @@ class Unpickler:
|
||||||
def load_binint2(self):
|
def load_binint2(self):
|
||||||
self.append(mloads('i' + self.read(2) + '\000\000'))
|
self.append(mloads('i' + self.read(2) + '\000\000'))
|
||||||
dispatch[BININT2] = load_binint2
|
dispatch[BININT2] = load_binint2
|
||||||
|
|
||||||
def load_long(self):
|
def load_long(self):
|
||||||
self.append(long(self.readline()[:-1], 0))
|
self.append(long(self.readline()[:-1], 0))
|
||||||
dispatch[LONG] = load_long
|
dispatch[LONG] = load_long
|
||||||
|
@ -710,7 +710,7 @@ class Unpickler:
|
||||||
k = self.marker()
|
k = self.marker()
|
||||||
klass = stack[k + 1]
|
klass = stack[k + 1]
|
||||||
del stack[k + 1]
|
del stack[k + 1]
|
||||||
args = tuple(stack[k + 1:])
|
args = tuple(stack[k + 1:])
|
||||||
del stack[k:]
|
del stack[k:]
|
||||||
instantiated = 0
|
instantiated = 0
|
||||||
if (not args and type(klass) is ClassType and
|
if (not args and type(klass) is ClassType and
|
||||||
|
@ -726,7 +726,7 @@ class Unpickler:
|
||||||
if not instantiated:
|
if not instantiated:
|
||||||
value = apply(klass, args)
|
value = apply(klass, args)
|
||||||
self.append(value)
|
self.append(value)
|
||||||
dispatch[OBJ] = load_obj
|
dispatch[OBJ] = load_obj
|
||||||
|
|
||||||
def load_global(self):
|
def load_global(self):
|
||||||
module = self.readline()[:-1]
|
module = self.readline()[:-1]
|
||||||
|
@ -761,8 +761,8 @@ class Unpickler:
|
||||||
safe = None
|
safe = None
|
||||||
|
|
||||||
if (not safe):
|
if (not safe):
|
||||||
raise UnpicklingError, "%s is not safe for " \
|
raise UnpicklingError, "%s is not safe for " \
|
||||||
"unpickling" % callable
|
"unpickling" % callable
|
||||||
|
|
||||||
if arg_tup is None:
|
if arg_tup is None:
|
||||||
value = callable.__basicnew__()
|
value = callable.__basicnew__()
|
||||||
|
@ -829,7 +829,7 @@ class Unpickler:
|
||||||
|
|
||||||
del stack[mark:]
|
del stack[mark:]
|
||||||
dispatch[APPENDS] = load_appends
|
dispatch[APPENDS] = load_appends
|
||||||
|
|
||||||
def load_setitem(self):
|
def load_setitem(self):
|
||||||
stack = self.stack
|
stack = self.stack
|
||||||
value = stack[-1]
|
value = stack[-1]
|
||||||
|
|
390
Lib/pipes.py
390
Lib/pipes.py
|
@ -69,229 +69,229 @@ import string
|
||||||
|
|
||||||
# Conversion step kinds
|
# Conversion step kinds
|
||||||
|
|
||||||
FILEIN_FILEOUT = 'ff' # Must read & write real files
|
FILEIN_FILEOUT = 'ff' # Must read & write real files
|
||||||
STDIN_FILEOUT = '-f' # Must write a real file
|
STDIN_FILEOUT = '-f' # Must write a real file
|
||||||
FILEIN_STDOUT = 'f-' # Must read a real file
|
FILEIN_STDOUT = 'f-' # Must read a real file
|
||||||
STDIN_STDOUT = '--' # Normal pipeline element
|
STDIN_STDOUT = '--' # Normal pipeline element
|
||||||
SOURCE = '.-' # Must be first, writes stdout
|
SOURCE = '.-' # Must be first, writes stdout
|
||||||
SINK = '-.' # Must be last, reads stdin
|
SINK = '-.' # Must be last, reads stdin
|
||||||
|
|
||||||
stepkinds = [FILEIN_FILEOUT, STDIN_FILEOUT, FILEIN_STDOUT, STDIN_STDOUT, \
|
stepkinds = [FILEIN_FILEOUT, STDIN_FILEOUT, FILEIN_STDOUT, STDIN_STDOUT, \
|
||||||
SOURCE, SINK]
|
SOURCE, SINK]
|
||||||
|
|
||||||
|
|
||||||
class Template:
|
class Template:
|
||||||
"""Class representing a pipeline template."""
|
"""Class representing a pipeline template."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Template() returns a fresh pipeline template."""
|
"""Template() returns a fresh pipeline template."""
|
||||||
self.debugging = 0
|
self.debugging = 0
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""t.__repr__() implements `t`."""
|
"""t.__repr__() implements `t`."""
|
||||||
return '<Template instance, steps=' + `self.steps` + '>'
|
return '<Template instance, steps=' + `self.steps` + '>'
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"""t.reset() restores a pipeline template to its initial state."""
|
"""t.reset() restores a pipeline template to its initial state."""
|
||||||
self.steps = []
|
self.steps = []
|
||||||
|
|
||||||
def clone(self):
|
def clone(self):
|
||||||
"""t.clone() returns a new pipeline template with identical
|
"""t.clone() returns a new pipeline template with identical
|
||||||
initial state as the current one."""
|
initial state as the current one."""
|
||||||
t = Template()
|
t = Template()
|
||||||
t.steps = self.steps[:]
|
t.steps = self.steps[:]
|
||||||
t.debugging = self.debugging
|
t.debugging = self.debugging
|
||||||
return t
|
return t
|
||||||
|
|
||||||
def debug(self, flag):
|
def debug(self, flag):
|
||||||
"""t.debug(flag) turns debugging on or off."""
|
"""t.debug(flag) turns debugging on or off."""
|
||||||
self.debugging = flag
|
self.debugging = flag
|
||||||
|
|
||||||
def append(self, cmd, kind):
|
def append(self, cmd, kind):
|
||||||
"""t.append(cmd, kind) adds a new step at the end."""
|
"""t.append(cmd, kind) adds a new step at the end."""
|
||||||
if type(cmd) is not type(''):
|
if type(cmd) is not type(''):
|
||||||
raise TypeError, \
|
raise TypeError, \
|
||||||
'Template.append: cmd must be a string'
|
'Template.append: cmd must be a string'
|
||||||
if kind not in stepkinds:
|
if kind not in stepkinds:
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.append: bad kind ' + `kind`
|
'Template.append: bad kind ' + `kind`
|
||||||
if kind == SOURCE:
|
if kind == SOURCE:
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.append: SOURCE can only be prepended'
|
'Template.append: SOURCE can only be prepended'
|
||||||
if self.steps and self.steps[-1][1] == SINK:
|
if self.steps and self.steps[-1][1] == SINK:
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.append: already ends with SINK'
|
'Template.append: already ends with SINK'
|
||||||
if kind[0] == 'f' and not re.search('\$IN\b', cmd):
|
if kind[0] == 'f' and not re.search('\$IN\b', cmd):
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.append: missing $IN in cmd'
|
'Template.append: missing $IN in cmd'
|
||||||
if kind[1] == 'f' and not re.search('\$OUT\b', cmd):
|
if kind[1] == 'f' and not re.search('\$OUT\b', cmd):
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.append: missing $OUT in cmd'
|
'Template.append: missing $OUT in cmd'
|
||||||
self.steps.append((cmd, kind))
|
self.steps.append((cmd, kind))
|
||||||
|
|
||||||
def prepend(self, cmd, kind):
|
def prepend(self, cmd, kind):
|
||||||
"""t.prepend(cmd, kind) adds a new step at the front."""
|
"""t.prepend(cmd, kind) adds a new step at the front."""
|
||||||
if type(cmd) is not type(''):
|
if type(cmd) is not type(''):
|
||||||
raise TypeError, \
|
raise TypeError, \
|
||||||
'Template.prepend: cmd must be a string'
|
'Template.prepend: cmd must be a string'
|
||||||
if kind not in stepkinds:
|
if kind not in stepkinds:
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.prepend: bad kind ' + `kind`
|
'Template.prepend: bad kind ' + `kind`
|
||||||
if kind == SINK:
|
if kind == SINK:
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.prepend: SINK can only be appended'
|
'Template.prepend: SINK can only be appended'
|
||||||
if self.steps and self.steps[0][1] == SOURCE:
|
if self.steps and self.steps[0][1] == SOURCE:
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.prepend: already begins with SOURCE'
|
'Template.prepend: already begins with SOURCE'
|
||||||
if kind[0] == 'f' and not re.search('\$IN\b', cmd):
|
if kind[0] == 'f' and not re.search('\$IN\b', cmd):
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.prepend: missing $IN in cmd'
|
'Template.prepend: missing $IN in cmd'
|
||||||
if kind[1] == 'f' and not re.search('\$OUT\b', cmd):
|
if kind[1] == 'f' and not re.search('\$OUT\b', cmd):
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.prepend: missing $OUT in cmd'
|
'Template.prepend: missing $OUT in cmd'
|
||||||
self.steps.insert(0, (cmd, kind))
|
self.steps.insert(0, (cmd, kind))
|
||||||
|
|
||||||
def open(self, file, rw):
|
def open(self, file, rw):
|
||||||
"""t.open(file, rw) returns a pipe or file object open for
|
"""t.open(file, rw) returns a pipe or file object open for
|
||||||
reading or writing; the file is the other end of the pipeline."""
|
reading or writing; the file is the other end of the pipeline."""
|
||||||
if rw == 'r':
|
if rw == 'r':
|
||||||
return self.open_r(file)
|
return self.open_r(file)
|
||||||
if rw == 'w':
|
if rw == 'w':
|
||||||
return self.open_w(file)
|
return self.open_w(file)
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.open: rw must be \'r\' or \'w\', not ' + `rw`
|
'Template.open: rw must be \'r\' or \'w\', not ' + `rw`
|
||||||
|
|
||||||
def open_r(self, file):
|
def open_r(self, file):
|
||||||
"""t.open_r(file) and t.open_w(file) implement
|
"""t.open_r(file) and t.open_w(file) implement
|
||||||
t.open(file, 'r') and t.open(file, 'w') respectively."""
|
t.open(file, 'r') and t.open(file, 'w') respectively."""
|
||||||
if not self.steps:
|
if not self.steps:
|
||||||
return open(file, 'r')
|
return open(file, 'r')
|
||||||
if self.steps[-1][1] == SINK:
|
if self.steps[-1][1] == SINK:
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.open_r: pipeline ends width SINK'
|
'Template.open_r: pipeline ends width SINK'
|
||||||
cmd = self.makepipeline(file, '')
|
cmd = self.makepipeline(file, '')
|
||||||
return os.popen(cmd, 'r')
|
return os.popen(cmd, 'r')
|
||||||
|
|
||||||
def open_w(self, file):
|
def open_w(self, file):
|
||||||
if not self.steps:
|
if not self.steps:
|
||||||
return open(file, 'w')
|
return open(file, 'w')
|
||||||
if self.steps[0][1] == SOURCE:
|
if self.steps[0][1] == SOURCE:
|
||||||
raise ValueError, \
|
raise ValueError, \
|
||||||
'Template.open_w: pipeline begins with SOURCE'
|
'Template.open_w: pipeline begins with SOURCE'
|
||||||
cmd = self.makepipeline('', file)
|
cmd = self.makepipeline('', file)
|
||||||
return os.popen(cmd, 'w')
|
return os.popen(cmd, 'w')
|
||||||
|
|
||||||
def copy(self, infile, outfile):
|
def copy(self, infile, outfile):
|
||||||
return os.system(self.makepipeline(infile, outfile))
|
return os.system(self.makepipeline(infile, outfile))
|
||||||
|
|
||||||
def makepipeline(self, infile, outfile):
|
def makepipeline(self, infile, outfile):
|
||||||
cmd = makepipeline(infile, self.steps, outfile)
|
cmd = makepipeline(infile, self.steps, outfile)
|
||||||
if self.debugging:
|
if self.debugging:
|
||||||
print cmd
|
print cmd
|
||||||
cmd = 'set -x; ' + cmd
|
cmd = 'set -x; ' + cmd
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
def makepipeline(infile, steps, outfile):
|
def makepipeline(infile, steps, outfile):
|
||||||
# Build a list with for each command:
|
# Build a list with for each command:
|
||||||
# [input filename or '', command string, kind, output filename or '']
|
# [input filename or '', command string, kind, output filename or '']
|
||||||
|
|
||||||
list = []
|
list = []
|
||||||
for cmd, kind in steps:
|
for cmd, kind in steps:
|
||||||
list.append(['', cmd, kind, ''])
|
list.append(['', cmd, kind, ''])
|
||||||
#
|
#
|
||||||
# Make sure there is at least one step
|
# Make sure there is at least one step
|
||||||
#
|
#
|
||||||
if not list:
|
if not list:
|
||||||
list.append(['', 'cat', '--', ''])
|
list.append(['', 'cat', '--', ''])
|
||||||
#
|
#
|
||||||
# Take care of the input and output ends
|
# Take care of the input and output ends
|
||||||
#
|
#
|
||||||
[cmd, kind] = list[0][1:3]
|
[cmd, kind] = list[0][1:3]
|
||||||
if kind[0] == 'f' and not infile:
|
if kind[0] == 'f' and not infile:
|
||||||
list.insert(0, ['', 'cat', '--', ''])
|
list.insert(0, ['', 'cat', '--', ''])
|
||||||
list[0][0] = infile
|
list[0][0] = infile
|
||||||
#
|
#
|
||||||
[cmd, kind] = list[-1][1:3]
|
[cmd, kind] = list[-1][1:3]
|
||||||
if kind[1] == 'f' and not outfile:
|
if kind[1] == 'f' and not outfile:
|
||||||
list.append(['', 'cat', '--', ''])
|
list.append(['', 'cat', '--', ''])
|
||||||
list[-1][-1] = outfile
|
list[-1][-1] = outfile
|
||||||
#
|
#
|
||||||
# Invent temporary files to connect stages that need files
|
# Invent temporary files to connect stages that need files
|
||||||
#
|
#
|
||||||
garbage = []
|
garbage = []
|
||||||
for i in range(1, len(list)):
|
for i in range(1, len(list)):
|
||||||
lkind = list[i-1][2]
|
lkind = list[i-1][2]
|
||||||
rkind = list[i][2]
|
rkind = list[i][2]
|
||||||
if lkind[1] == 'f' or rkind[0] == 'f':
|
if lkind[1] == 'f' or rkind[0] == 'f':
|
||||||
temp = tempfile.mktemp()
|
temp = tempfile.mktemp()
|
||||||
garbage.append(temp)
|
garbage.append(temp)
|
||||||
list[i-1][-1] = list[i][0] = temp
|
list[i-1][-1] = list[i][0] = temp
|
||||||
#
|
#
|
||||||
for item in list:
|
for item in list:
|
||||||
[inf, cmd, kind, outf] = item
|
[inf, cmd, kind, outf] = item
|
||||||
if kind[1] == 'f':
|
if kind[1] == 'f':
|
||||||
cmd = 'OUT=' + quote(outf) + '; ' + cmd
|
cmd = 'OUT=' + quote(outf) + '; ' + cmd
|
||||||
if kind[0] == 'f':
|
if kind[0] == 'f':
|
||||||
cmd = 'IN=' + quote(inf) + '; ' + cmd
|
cmd = 'IN=' + quote(inf) + '; ' + cmd
|
||||||
if kind[0] == '-' and inf:
|
if kind[0] == '-' and inf:
|
||||||
cmd = cmd + ' <' + quote(inf)
|
cmd = cmd + ' <' + quote(inf)
|
||||||
if kind[1] == '-' and outf:
|
if kind[1] == '-' and outf:
|
||||||
cmd = cmd + ' >' + quote(outf)
|
cmd = cmd + ' >' + quote(outf)
|
||||||
item[1] = cmd
|
item[1] = cmd
|
||||||
#
|
#
|
||||||
cmdlist = list[0][1]
|
cmdlist = list[0][1]
|
||||||
for item in list[1:]:
|
for item in list[1:]:
|
||||||
[cmd, kind] = item[1:3]
|
[cmd, kind] = item[1:3]
|
||||||
if item[0] == '':
|
if item[0] == '':
|
||||||
if 'f' in kind:
|
if 'f' in kind:
|
||||||
cmd = '{ ' + cmd + '; }'
|
cmd = '{ ' + cmd + '; }'
|
||||||
cmdlist = cmdlist + ' |\n' + cmd
|
cmdlist = cmdlist + ' |\n' + cmd
|
||||||
else:
|
else:
|
||||||
cmdlist = cmdlist + '\n' + cmd
|
cmdlist = cmdlist + '\n' + cmd
|
||||||
#
|
#
|
||||||
if garbage:
|
if garbage:
|
||||||
rmcmd = 'rm -f'
|
rmcmd = 'rm -f'
|
||||||
for file in garbage:
|
for file in garbage:
|
||||||
rmcmd = rmcmd + ' ' + quote(file)
|
rmcmd = rmcmd + ' ' + quote(file)
|
||||||
trapcmd = 'trap ' + quote(rmcmd + '; exit') + ' 1 2 3 13 14 15'
|
trapcmd = 'trap ' + quote(rmcmd + '; exit') + ' 1 2 3 13 14 15'
|
||||||
cmdlist = trapcmd + '\n' + cmdlist + '\n' + rmcmd
|
cmdlist = trapcmd + '\n' + cmdlist + '\n' + rmcmd
|
||||||
#
|
#
|
||||||
return cmdlist
|
return cmdlist
|
||||||
|
|
||||||
|
|
||||||
# Reliably quote a string as a single argument for /bin/sh
|
# Reliably quote a string as a single argument for /bin/sh
|
||||||
|
|
||||||
_safechars = string.letters + string.digits + '!@%_-+=:,./' # Safe unquoted
|
_safechars = string.letters + string.digits + '!@%_-+=:,./' # Safe unquoted
|
||||||
_funnychars = '"`$\\' # Unsafe inside "double quotes"
|
_funnychars = '"`$\\' # Unsafe inside "double quotes"
|
||||||
|
|
||||||
def quote(file):
|
def quote(file):
|
||||||
for c in file:
|
for c in file:
|
||||||
if c not in _safechars:
|
if c not in _safechars:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
return file
|
return file
|
||||||
if '\'' not in file:
|
if '\'' not in file:
|
||||||
return '\'' + file + '\''
|
return '\'' + file + '\''
|
||||||
res = ''
|
res = ''
|
||||||
for c in file:
|
for c in file:
|
||||||
if c in _funnychars:
|
if c in _funnychars:
|
||||||
c = '\\' + c
|
c = '\\' + c
|
||||||
res = res + c
|
res = res + c
|
||||||
return '"' + res + '"'
|
return '"' + res + '"'
|
||||||
|
|
||||||
|
|
||||||
# Small test program and example
|
# Small test program and example
|
||||||
|
|
||||||
def test():
|
def test():
|
||||||
print 'Testing...'
|
print 'Testing...'
|
||||||
t = Template()
|
t = Template()
|
||||||
t.append('togif $IN $OUT', 'ff')
|
t.append('togif $IN $OUT', 'ff')
|
||||||
t.append('giftoppm', '--')
|
t.append('giftoppm', '--')
|
||||||
t.append('ppmtogif >$OUT', '-f')
|
t.append('ppmtogif >$OUT', '-f')
|
||||||
t.append('fromgif $IN $OUT', 'ff')
|
t.append('fromgif $IN $OUT', 'ff')
|
||||||
t.debug(1)
|
t.debug(1)
|
||||||
FILE = '/usr/local/images/rgb/rogues/guido.rgb'
|
FILE = '/usr/local/images/rgb/rogues/guido.rgb'
|
||||||
t.copy(FILE, '@temp')
|
t.copy(FILE, '@temp')
|
||||||
print 'Done.'
|
print 'Done.'
|
||||||
|
|
430
Lib/poplib.py
430
Lib/poplib.py
|
@ -32,290 +32,290 @@ CRLF = CR+LF
|
||||||
|
|
||||||
class POP3:
|
class POP3:
|
||||||
|
|
||||||
"""This class supports both the minimal and optional command sets.
|
"""This class supports both the minimal and optional command sets.
|
||||||
Arguments can be strings or integers (where appropriate)
|
Arguments can be strings or integers (where appropriate)
|
||||||
(e.g.: retr(1) and retr('1') both work equally well.
|
(e.g.: retr(1) and retr('1') both work equally well.
|
||||||
|
|
||||||
Minimal Command Set:
|
Minimal Command Set:
|
||||||
USER name user(name)
|
USER name user(name)
|
||||||
PASS string pass_(string)
|
PASS string pass_(string)
|
||||||
STAT stat()
|
STAT stat()
|
||||||
LIST [msg] list(msg = None)
|
LIST [msg] list(msg = None)
|
||||||
RETR msg retr(msg)
|
RETR msg retr(msg)
|
||||||
DELE msg dele(msg)
|
DELE msg dele(msg)
|
||||||
NOOP noop()
|
NOOP noop()
|
||||||
RSET rset()
|
RSET rset()
|
||||||
QUIT quit()
|
QUIT quit()
|
||||||
|
|
||||||
Optional Commands (some servers support these):
|
Optional Commands (some servers support these):
|
||||||
RPOP name rpop(name)
|
RPOP name rpop(name)
|
||||||
APOP name digest apop(name, digest)
|
APOP name digest apop(name, digest)
|
||||||
TOP msg n top(msg, n)
|
TOP msg n top(msg, n)
|
||||||
UIDL [msg] uidl(msg = None)
|
UIDL [msg] uidl(msg = None)
|
||||||
|
|
||||||
Raises one exception: 'error_proto'.
|
Raises one exception: 'error_proto'.
|
||||||
|
|
||||||
Instantiate with:
|
Instantiate with:
|
||||||
POP3(hostname, port=110)
|
POP3(hostname, port=110)
|
||||||
|
|
||||||
NB: the POP protocol locks the mailbox from user
|
NB: the POP protocol locks the mailbox from user
|
||||||
authorization until QUIT, so be sure to get in, suck
|
authorization until QUIT, so be sure to get in, suck
|
||||||
the messages, and quit, each time you access the
|
the messages, and quit, each time you access the
|
||||||
mailbox.
|
mailbox.
|
||||||
|
|
||||||
POP is a line-based protocol, which means large mail
|
POP is a line-based protocol, which means large mail
|
||||||
messages consume lots of python cycles reading them
|
messages consume lots of python cycles reading them
|
||||||
line-by-line.
|
line-by-line.
|
||||||
|
|
||||||
If it's available on your mail server, use IMAP4
|
If it's available on your mail server, use IMAP4
|
||||||
instead, it doesn't suffer from the two problems
|
instead, it doesn't suffer from the two problems
|
||||||
above.
|
above.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, host, port = POP3_PORT):
|
def __init__(self, host, port = POP3_PORT):
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.sock.connect((self.host, self.port))
|
self.sock.connect((self.host, self.port))
|
||||||
self.file = self.sock.makefile('rb')
|
self.file = self.sock.makefile('rb')
|
||||||
self._debugging = 0
|
self._debugging = 0
|
||||||
self.welcome = self._getresp()
|
self.welcome = self._getresp()
|
||||||
|
|
||||||
|
|
||||||
def _putline(self, line):
|
def _putline(self, line):
|
||||||
#if self._debugging > 1: print '*put*', `line`
|
#if self._debugging > 1: print '*put*', `line`
|
||||||
self.sock.send('%s%s' % (line, CRLF))
|
self.sock.send('%s%s' % (line, CRLF))
|
||||||
|
|
||||||
|
|
||||||
# Internal: send one command to the server (through _putline())
|
# Internal: send one command to the server (through _putline())
|
||||||
|
|
||||||
def _putcmd(self, line):
|
def _putcmd(self, line):
|
||||||
#if self._debugging: print '*cmd*', `line`
|
#if self._debugging: print '*cmd*', `line`
|
||||||
self._putline(line)
|
self._putline(line)
|
||||||
|
|
||||||
|
|
||||||
# Internal: return one line from the server, stripping CRLF.
|
# Internal: return one line from the server, stripping CRLF.
|
||||||
# This is where all the CPU time of this module is consumed.
|
# This is where all the CPU time of this module is consumed.
|
||||||
# Raise error_proto('-ERR EOF') if the connection is closed.
|
# Raise error_proto('-ERR EOF') if the connection is closed.
|
||||||
|
|
||||||
def _getline(self):
|
def _getline(self):
|
||||||
line = self.file.readline()
|
line = self.file.readline()
|
||||||
#if self._debugging > 1: print '*get*', `line`
|
#if self._debugging > 1: print '*get*', `line`
|
||||||
if not line: raise error_proto('-ERR EOF')
|
if not line: raise error_proto('-ERR EOF')
|
||||||
octets = len(line)
|
octets = len(line)
|
||||||
# server can send any combination of CR & LF
|
# server can send any combination of CR & LF
|
||||||
# however, 'readline()' returns lines ending in LF
|
# however, 'readline()' returns lines ending in LF
|
||||||
# so only possibilities are ...LF, ...CRLF, CR...LF
|
# so only possibilities are ...LF, ...CRLF, CR...LF
|
||||||
if line[-2:] == CRLF:
|
if line[-2:] == CRLF:
|
||||||
return line[:-2], octets
|
return line[:-2], octets
|
||||||
if line[0] == CR:
|
if line[0] == CR:
|
||||||
return line[1:-1], octets
|
return line[1:-1], octets
|
||||||
return line[:-1], octets
|
return line[:-1], octets
|
||||||
|
|
||||||
|
|
||||||
# Internal: get a response from the server.
|
# Internal: get a response from the server.
|
||||||
# Raise 'error_proto' if the response doesn't start with '+'.
|
# Raise 'error_proto' if the response doesn't start with '+'.
|
||||||
|
|
||||||
def _getresp(self):
|
def _getresp(self):
|
||||||
resp, o = self._getline()
|
resp, o = self._getline()
|
||||||
#if self._debugging > 1: print '*resp*', `resp`
|
#if self._debugging > 1: print '*resp*', `resp`
|
||||||
c = resp[:1]
|
c = resp[:1]
|
||||||
if c != '+':
|
if c != '+':
|
||||||
raise error_proto(resp)
|
raise error_proto(resp)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
# Internal: get a response plus following text from the server.
|
# Internal: get a response plus following text from the server.
|
||||||
|
|
||||||
def _getlongresp(self):
|
def _getlongresp(self):
|
||||||
resp = self._getresp()
|
resp = self._getresp()
|
||||||
list = []; octets = 0
|
list = []; octets = 0
|
||||||
line, o = self._getline()
|
line, o = self._getline()
|
||||||
while line != '.':
|
while line != '.':
|
||||||
if line[:2] == '..':
|
if line[:2] == '..':
|
||||||
o = o-1
|
o = o-1
|
||||||
line = line[1:]
|
line = line[1:]
|
||||||
octets = octets + o
|
octets = octets + o
|
||||||
list.append(line)
|
list.append(line)
|
||||||
line, o = self._getline()
|
line, o = self._getline()
|
||||||
return resp, list, octets
|
return resp, list, octets
|
||||||
|
|
||||||
|
|
||||||
# Internal: send a command and get the response
|
# Internal: send a command and get the response
|
||||||
|
|
||||||
def _shortcmd(self, line):
|
def _shortcmd(self, line):
|
||||||
self._putcmd(line)
|
self._putcmd(line)
|
||||||
return self._getresp()
|
return self._getresp()
|
||||||
|
|
||||||
|
|
||||||
# Internal: send a command and get the response plus following text
|
# Internal: send a command and get the response plus following text
|
||||||
|
|
||||||
def _longcmd(self, line):
|
def _longcmd(self, line):
|
||||||
self._putcmd(line)
|
self._putcmd(line)
|
||||||
return self._getlongresp()
|
return self._getlongresp()
|
||||||
|
|
||||||
|
|
||||||
# These can be useful:
|
# These can be useful:
|
||||||
|
|
||||||
def getwelcome(self):
|
def getwelcome(self):
|
||||||
return self.welcome
|
return self.welcome
|
||||||
|
|
||||||
|
|
||||||
def set_debuglevel(self, level):
|
def set_debuglevel(self, level):
|
||||||
self._debugging = level
|
self._debugging = level
|
||||||
|
|
||||||
|
|
||||||
# Here are all the POP commands:
|
# Here are all the POP commands:
|
||||||
|
|
||||||
def user(self, user):
|
def user(self, user):
|
||||||
"""Send user name, return response
|
"""Send user name, return response
|
||||||
|
|
||||||
(should indicate password required).
|
|
||||||
"""
|
|
||||||
return self._shortcmd('USER %s' % user)
|
|
||||||
|
|
||||||
|
(should indicate password required).
|
||||||
|
"""
|
||||||
|
return self._shortcmd('USER %s' % user)
|
||||||
|
|
||||||
def pass_(self, pswd):
|
|
||||||
"""Send password, return response
|
|
||||||
|
|
||||||
(response includes message count, mailbox size).
|
|
||||||
|
|
||||||
NB: mailbox is locked by server from here to 'quit()'
|
def pass_(self, pswd):
|
||||||
"""
|
"""Send password, return response
|
||||||
return self._shortcmd('PASS %s' % pswd)
|
|
||||||
|
|
||||||
|
(response includes message count, mailbox size).
|
||||||
|
|
||||||
def stat(self):
|
NB: mailbox is locked by server from here to 'quit()'
|
||||||
"""Get mailbox status.
|
"""
|
||||||
|
return self._shortcmd('PASS %s' % pswd)
|
||||||
Result is tuple of 2 ints (message count, mailbox size)
|
|
||||||
"""
|
|
||||||
retval = self._shortcmd('STAT')
|
|
||||||
rets = string.split(retval)
|
|
||||||
#if self._debugging: print '*stat*', `rets`
|
|
||||||
numMessages = string.atoi(rets[1])
|
|
||||||
sizeMessages = string.atoi(rets[2])
|
|
||||||
return (numMessages, sizeMessages)
|
|
||||||
|
|
||||||
|
|
||||||
def list(self, which=None):
|
def stat(self):
|
||||||
"""Request listing, return result.
|
"""Get mailbox status.
|
||||||
|
|
||||||
Result without a message number argument is in form
|
Result is tuple of 2 ints (message count, mailbox size)
|
||||||
['response', ['mesg_num octets', ...]].
|
"""
|
||||||
|
retval = self._shortcmd('STAT')
|
||||||
|
rets = string.split(retval)
|
||||||
|
#if self._debugging: print '*stat*', `rets`
|
||||||
|
numMessages = string.atoi(rets[1])
|
||||||
|
sizeMessages = string.atoi(rets[2])
|
||||||
|
return (numMessages, sizeMessages)
|
||||||
|
|
||||||
Result when a message number argument is given is a
|
|
||||||
single response: the "scan listing" for that message.
|
|
||||||
"""
|
|
||||||
if which:
|
|
||||||
return self._shortcmd('LIST %s' % which)
|
|
||||||
return self._longcmd('LIST')
|
|
||||||
|
|
||||||
|
def list(self, which=None):
|
||||||
|
"""Request listing, return result.
|
||||||
|
|
||||||
def retr(self, which):
|
Result without a message number argument is in form
|
||||||
"""Retrieve whole message number 'which'.
|
['response', ['mesg_num octets', ...]].
|
||||||
|
|
||||||
Result is in form ['response', ['line', ...], octets].
|
Result when a message number argument is given is a
|
||||||
"""
|
single response: the "scan listing" for that message.
|
||||||
return self._longcmd('RETR %s' % which)
|
"""
|
||||||
|
if which:
|
||||||
|
return self._shortcmd('LIST %s' % which)
|
||||||
|
return self._longcmd('LIST')
|
||||||
|
|
||||||
|
|
||||||
def dele(self, which):
|
def retr(self, which):
|
||||||
"""Delete message number 'which'.
|
"""Retrieve whole message number 'which'.
|
||||||
|
|
||||||
Result is 'response'.
|
Result is in form ['response', ['line', ...], octets].
|
||||||
"""
|
"""
|
||||||
return self._shortcmd('DELE %s' % which)
|
return self._longcmd('RETR %s' % which)
|
||||||
|
|
||||||
|
|
||||||
def noop(self):
|
def dele(self, which):
|
||||||
"""Does nothing.
|
"""Delete message number 'which'.
|
||||||
|
|
||||||
One supposes the response indicates the server is alive.
|
|
||||||
"""
|
|
||||||
return self._shortcmd('NOOP')
|
|
||||||
|
|
||||||
|
Result is 'response'.
|
||||||
|
"""
|
||||||
|
return self._shortcmd('DELE %s' % which)
|
||||||
|
|
||||||
def rset(self):
|
|
||||||
"""Not sure what this does."""
|
|
||||||
return self._shortcmd('RSET')
|
|
||||||
|
|
||||||
|
def noop(self):
|
||||||
|
"""Does nothing.
|
||||||
|
|
||||||
def quit(self):
|
One supposes the response indicates the server is alive.
|
||||||
"""Signoff: commit changes on server, unlock mailbox, close connection."""
|
"""
|
||||||
try:
|
return self._shortcmd('NOOP')
|
||||||
resp = self._shortcmd('QUIT')
|
|
||||||
except error_proto, val:
|
|
||||||
resp = val
|
|
||||||
self.file.close()
|
|
||||||
self.sock.close()
|
|
||||||
del self.file, self.sock
|
|
||||||
return resp
|
|
||||||
|
|
||||||
#__del__ = quit
|
|
||||||
|
|
||||||
|
def rset(self):
|
||||||
|
"""Not sure what this does."""
|
||||||
|
return self._shortcmd('RSET')
|
||||||
|
|
||||||
# optional commands:
|
|
||||||
|
|
||||||
def rpop(self, user):
|
def quit(self):
|
||||||
"""Not sure what this does."""
|
"""Signoff: commit changes on server, unlock mailbox, close connection."""
|
||||||
return self._shortcmd('RPOP %s' % user)
|
try:
|
||||||
|
resp = self._shortcmd('QUIT')
|
||||||
|
except error_proto, val:
|
||||||
|
resp = val
|
||||||
|
self.file.close()
|
||||||
|
self.sock.close()
|
||||||
|
del self.file, self.sock
|
||||||
|
return resp
|
||||||
|
|
||||||
|
#__del__ = quit
|
||||||
|
|
||||||
timestamp = regex.compile('\+OK.*\(<[^>]+>\)')
|
|
||||||
|
|
||||||
def apop(self, user, secret):
|
# optional commands:
|
||||||
"""Authorisation
|
|
||||||
|
|
||||||
- only possible if server has supplied a timestamp in initial greeting.
|
|
||||||
|
|
||||||
Args:
|
def rpop(self, user):
|
||||||
user - mailbox user;
|
"""Not sure what this does."""
|
||||||
secret - secret shared between client and server.
|
return self._shortcmd('RPOP %s' % user)
|
||||||
|
|
||||||
NB: mailbox is locked by server from here to 'quit()'
|
|
||||||
"""
|
|
||||||
if self.timestamp.match(self.welcome) <= 0:
|
|
||||||
raise error_proto('-ERR APOP not supported by server')
|
|
||||||
import md5
|
|
||||||
digest = md5.new(self.timestamp.group(1)+secret).digest()
|
|
||||||
digest = string.join(map(lambda x:'%02x'%ord(x), digest), '')
|
|
||||||
return self._shortcmd('APOP %s %s' % (user, digest))
|
|
||||||
|
|
||||||
|
timestamp = regex.compile('\+OK.*\(<[^>]+>\)')
|
||||||
|
|
||||||
def top(self, which, howmuch):
|
def apop(self, user, secret):
|
||||||
"""Retrieve message header of message number 'which'
|
"""Authorisation
|
||||||
and first 'howmuch' lines of message body.
|
|
||||||
|
|
||||||
Result is in form ['response', ['line', ...], octets].
|
- only possible if server has supplied a timestamp in initial greeting.
|
||||||
"""
|
|
||||||
return self._longcmd('TOP %s %s' % (which, howmuch))
|
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user - mailbox user;
|
||||||
|
secret - secret shared between client and server.
|
||||||
|
|
||||||
def uidl(self, which=None):
|
NB: mailbox is locked by server from here to 'quit()'
|
||||||
"""Return message digest (unique id) list.
|
"""
|
||||||
|
if self.timestamp.match(self.welcome) <= 0:
|
||||||
|
raise error_proto('-ERR APOP not supported by server')
|
||||||
|
import md5
|
||||||
|
digest = md5.new(self.timestamp.group(1)+secret).digest()
|
||||||
|
digest = string.join(map(lambda x:'%02x'%ord(x), digest), '')
|
||||||
|
return self._shortcmd('APOP %s %s' % (user, digest))
|
||||||
|
|
||||||
|
|
||||||
|
def top(self, which, howmuch):
|
||||||
|
"""Retrieve message header of message number 'which'
|
||||||
|
and first 'howmuch' lines of message body.
|
||||||
|
|
||||||
|
Result is in form ['response', ['line', ...], octets].
|
||||||
|
"""
|
||||||
|
return self._longcmd('TOP %s %s' % (which, howmuch))
|
||||||
|
|
||||||
|
|
||||||
|
def uidl(self, which=None):
|
||||||
|
"""Return message digest (unique id) list.
|
||||||
|
|
||||||
|
If 'which', result contains unique id for that message
|
||||||
|
in the form 'response mesgnum uid', otherwise result is
|
||||||
|
the list ['response', ['mesgnum uid', ...], octets]
|
||||||
|
"""
|
||||||
|
if which:
|
||||||
|
return self._shortcmd('UIDL %s' % which)
|
||||||
|
return self._longcmd('UIDL')
|
||||||
|
|
||||||
If 'which', result contains unique id for that message
|
|
||||||
in the form 'response mesgnum uid', otherwise result is
|
|
||||||
the list ['response', ['mesgnum uid', ...], octets]
|
|
||||||
"""
|
|
||||||
if which:
|
|
||||||
return self._shortcmd('UIDL %s' % which)
|
|
||||||
return self._longcmd('UIDL')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
a = POP3(TESTSERVER)
|
a = POP3(TESTSERVER)
|
||||||
print a.getwelcome()
|
print a.getwelcome()
|
||||||
a.user(TESTACCOUNT)
|
a.user(TESTACCOUNT)
|
||||||
a.pass_(TESTPASSWORD)
|
a.pass_(TESTPASSWORD)
|
||||||
a.list()
|
a.list()
|
||||||
(numMsgs, totalSize) = a.stat()
|
(numMsgs, totalSize) = a.stat()
|
||||||
for i in range(1, numMsgs + 1):
|
for i in range(1, numMsgs + 1):
|
||||||
(header, msg, octets) = a.retr(i)
|
(header, msg, octets) = a.retr(i)
|
||||||
print "Message ", `i`, ':'
|
print "Message ", `i`, ':'
|
||||||
for line in msg:
|
for line in msg:
|
||||||
print ' ' + line
|
print ' ' + line
|
||||||
print '-----------------------'
|
print '-----------------------'
|
||||||
a.quit()
|
a.quit()
|
||||||
|
|
|
@ -129,7 +129,7 @@ class _posixfile_:
|
||||||
|
|
||||||
l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFL, l_flags)
|
l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFL, l_flags)
|
||||||
|
|
||||||
if 'c' in which:
|
if 'c' in which:
|
||||||
arg = ('!' not in which) # 0 is don't, 1 is do close on exec
|
arg = ('!' not in which) # 0 is don't, 1 is do close on exec
|
||||||
l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFD, arg)
|
l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFD, arg)
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ class _posixfile_:
|
||||||
if FCNTL.O_NDELAY & l_flags: which = which + 'n'
|
if FCNTL.O_NDELAY & l_flags: which = which + 'n'
|
||||||
if FCNTL.O_SYNC & l_flags: which = which + 's'
|
if FCNTL.O_SYNC & l_flags: which = which + 's'
|
||||||
return which
|
return which
|
||||||
|
|
||||||
def lock(self, how, *args):
|
def lock(self, how, *args):
|
||||||
import struct, fcntl, FCNTL
|
import struct, fcntl, FCNTL
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ class _posixfile_:
|
||||||
'freebsd2', 'freebsd3', 'freebsd4', 'freebsd5',
|
'freebsd2', 'freebsd3', 'freebsd4', 'freebsd5',
|
||||||
'bsdos2', 'bsdos3', 'bsdos4'):
|
'bsdos2', 'bsdos3', 'bsdos4'):
|
||||||
flock = struct.pack('lxxxxlxxxxlhh', \
|
flock = struct.pack('lxxxxlxxxxlhh', \
|
||||||
l_start, l_len, os.getpid(), l_type, l_whence)
|
l_start, l_len, os.getpid(), l_type, l_whence)
|
||||||
elif sys.platform in ['aix3', 'aix4']:
|
elif sys.platform in ['aix3', 'aix4']:
|
||||||
flock = struct.pack('hhlllii', \
|
flock = struct.pack('hhlllii', \
|
||||||
l_type, l_whence, l_start, l_len, 0, 0, 0)
|
l_type, l_whence, l_start, l_len, 0, 0, 0)
|
||||||
|
|
|
@ -55,7 +55,7 @@ def join(a, *p):
|
||||||
# Trailing '/'es are stripped from head unless it is the root.
|
# Trailing '/'es are stripped from head unless it is the root.
|
||||||
|
|
||||||
def split(p):
|
def split(p):
|
||||||
"""Split a pathname. Returns tuple "(head, tail)" where "tail" is
|
"""Split a pathname. Returns tuple "(head, tail)" where "tail" is
|
||||||
everything after the final slash. Either part may be empty."""
|
everything after the final slash. Either part may be empty."""
|
||||||
i = p.rfind('/') + 1
|
i = p.rfind('/') + 1
|
||||||
head, tail = p[:i], p[i:]
|
head, tail = p[:i], p[i:]
|
||||||
|
@ -93,7 +93,7 @@ def splitext(p):
|
||||||
# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
|
# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
|
||||||
|
|
||||||
def splitdrive(p):
|
def splitdrive(p):
|
||||||
"""Split a pathname into drive and path. On Posix, drive is always
|
"""Split a pathname into drive and path. On Posix, drive is always
|
||||||
empty."""
|
empty."""
|
||||||
return '', p
|
return '', p
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ def sameopenfile(fp1, fp2):
|
||||||
def samestat(s1, s2):
|
def samestat(s1, s2):
|
||||||
"""Test whether two stat buffers reference the same file"""
|
"""Test whether two stat buffers reference the same file"""
|
||||||
return s1[stat.ST_INO] == s2[stat.ST_INO] and \
|
return s1[stat.ST_INO] == s2[stat.ST_INO] and \
|
||||||
s1[stat.ST_DEV] == s2[stat.ST_DEV]
|
s1[stat.ST_DEV] == s2[stat.ST_DEV]
|
||||||
|
|
||||||
|
|
||||||
# Is a path a mount point?
|
# Is a path a mount point?
|
||||||
|
@ -253,7 +253,7 @@ def ismount(path):
|
||||||
# or to impose a different order of visiting.
|
# or to impose a different order of visiting.
|
||||||
|
|
||||||
def walk(top, func, arg):
|
def walk(top, func, arg):
|
||||||
"""walk(top,func,arg) calls func(arg, d, files) for each directory "d"
|
"""walk(top,func,arg) calls func(arg, d, files) for each directory "d"
|
||||||
in the tree rooted at "top" (including "top" itself). "files" is a list
|
in the tree rooted at "top" (including "top" itself). "files" is a list
|
||||||
of all the files and subdirs in directory "d".
|
of all the files and subdirs in directory "d".
|
||||||
"""
|
"""
|
||||||
|
@ -263,10 +263,10 @@ def walk(top, func, arg):
|
||||||
return
|
return
|
||||||
func(arg, top, names)
|
func(arg, top, names)
|
||||||
for name in names:
|
for name in names:
|
||||||
name = join(top, name)
|
name = join(top, name)
|
||||||
st = os.lstat(name)
|
st = os.lstat(name)
|
||||||
if stat.S_ISDIR(st[stat.ST_MODE]):
|
if stat.S_ISDIR(st[stat.ST_MODE]):
|
||||||
walk(name, func, arg)
|
walk(name, func, arg)
|
||||||
|
|
||||||
|
|
||||||
# Expand paths beginning with '~' or '~user'.
|
# Expand paths beginning with '~' or '~user'.
|
||||||
|
@ -279,7 +279,7 @@ def walk(top, func, arg):
|
||||||
# variable expansion.)
|
# variable expansion.)
|
||||||
|
|
||||||
def expanduser(path):
|
def expanduser(path):
|
||||||
"""Expand ~ and ~user constructions. If user or $HOME is unknown,
|
"""Expand ~ and ~user constructions. If user or $HOME is unknown,
|
||||||
do nothing."""
|
do nothing."""
|
||||||
if path[:1] != '~':
|
if path[:1] != '~':
|
||||||
return path
|
return path
|
||||||
|
@ -349,7 +349,7 @@ def normpath(path):
|
||||||
for comp in comps:
|
for comp in comps:
|
||||||
if comp in ('', '.'):
|
if comp in ('', '.'):
|
||||||
continue
|
continue
|
||||||
if (comp != '..' or (not initial_slash and not new_comps) or
|
if (comp != '..' or (not initial_slash and not new_comps) or
|
||||||
(new_comps and new_comps[-1] == '..')):
|
(new_comps and new_comps[-1] == '..')):
|
||||||
new_comps.append(comp)
|
new_comps.append(comp)
|
||||||
elif new_comps:
|
elif new_comps:
|
||||||
|
|
94
Lib/pre.py
94
Lib/pre.py
|
@ -44,7 +44,7 @@ below. If the ordinary character is not on the list, then the
|
||||||
resulting RE will match the second character.
|
resulting RE will match the second character.
|
||||||
\\number Matches the contents of the group of the same number.
|
\\number Matches the contents of the group of the same number.
|
||||||
\\A Matches only at the start of the string.
|
\\A Matches only at the start of the string.
|
||||||
\\Z Matches only at the end of the string.
|
\\Z Matches only at the end of the string.
|
||||||
\\b Matches the empty string, but only at the start or end of a word.
|
\\b Matches the empty string, but only at the start or end of a word.
|
||||||
\\B Matches the empty string, but not at the start or end of a word.
|
\\B Matches the empty string, but not at the start or end of a word.
|
||||||
\\d Matches any decimal digit; equivalent to the set [0-9].
|
\\d Matches any decimal digit; equivalent to the set [0-9].
|
||||||
|
@ -55,7 +55,7 @@ resulting RE will match the second character.
|
||||||
With LOCALE, it will match the set [0-9_] plus characters defined
|
With LOCALE, it will match the set [0-9_] plus characters defined
|
||||||
as letters for the current locale.
|
as letters for the current locale.
|
||||||
\\W Matches the complement of \\w.
|
\\W Matches the complement of \\w.
|
||||||
\\\\ Matches a literal backslash.
|
\\\\ Matches a literal backslash.
|
||||||
|
|
||||||
This module exports the following functions:
|
This module exports the following functions:
|
||||||
match Match a regular expression pattern to the beginning of a string.
|
match Match a regular expression pattern to the beginning of a string.
|
||||||
|
@ -100,8 +100,8 @@ from pcre import *
|
||||||
I = IGNORECASE
|
I = IGNORECASE
|
||||||
L = LOCALE
|
L = LOCALE
|
||||||
M = MULTILINE
|
M = MULTILINE
|
||||||
S = DOTALL
|
S = DOTALL
|
||||||
X = VERBOSE
|
X = VERBOSE
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -125,7 +125,7 @@ def _cachecompile(pattern, flags=0):
|
||||||
|
|
||||||
def match(pattern, string, flags=0):
|
def match(pattern, string, flags=0):
|
||||||
"""match (pattern, string[, flags]) -> MatchObject or None
|
"""match (pattern, string[, flags]) -> MatchObject or None
|
||||||
|
|
||||||
If zero or more characters at the beginning of string match the
|
If zero or more characters at the beginning of string match the
|
||||||
regular expression pattern, return a corresponding MatchObject
|
regular expression pattern, return a corresponding MatchObject
|
||||||
instance. Return None if the string does not match the pattern;
|
instance. Return None if the string does not match the pattern;
|
||||||
|
@ -135,12 +135,12 @@ def match(pattern, string, flags=0):
|
||||||
search() instead.
|
search() instead.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return _cachecompile(pattern, flags).match(string)
|
return _cachecompile(pattern, flags).match(string)
|
||||||
|
|
||||||
def search(pattern, string, flags=0):
|
def search(pattern, string, flags=0):
|
||||||
"""search (pattern, string[, flags]) -> MatchObject or None
|
"""search (pattern, string[, flags]) -> MatchObject or None
|
||||||
|
|
||||||
Scan through string looking for a location where the regular
|
Scan through string looking for a location where the regular
|
||||||
expression pattern produces a match, and return a corresponding
|
expression pattern produces a match, and return a corresponding
|
||||||
MatchObject instance. Return None if no position in the string
|
MatchObject instance. Return None if no position in the string
|
||||||
|
@ -149,10 +149,10 @@ def search(pattern, string, flags=0):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return _cachecompile(pattern, flags).search(string)
|
return _cachecompile(pattern, flags).search(string)
|
||||||
|
|
||||||
def sub(pattern, repl, string, count=0):
|
def sub(pattern, repl, string, count=0):
|
||||||
"""sub(pattern, repl, string[, count=0]) -> string
|
"""sub(pattern, repl, string[, count=0]) -> string
|
||||||
|
|
||||||
Return the string obtained by replacing the leftmost
|
Return the string obtained by replacing the leftmost
|
||||||
non-overlapping occurrences of pattern in string by the
|
non-overlapping occurrences of pattern in string by the
|
||||||
replacement repl. If the pattern isn't found, string is returned
|
replacement repl. If the pattern isn't found, string is returned
|
||||||
|
@ -177,7 +177,7 @@ def sub(pattern, repl, string, count=0):
|
||||||
|
|
||||||
def subn(pattern, repl, string, count=0):
|
def subn(pattern, repl, string, count=0):
|
||||||
"""subn(pattern, repl, string[, count=0]) -> (string, num substitutions)
|
"""subn(pattern, repl, string[, count=0]) -> (string, num substitutions)
|
||||||
|
|
||||||
Perform the same operation as sub(), but return a tuple
|
Perform the same operation as sub(), but return a tuple
|
||||||
(new_string, number_of_subs_made).
|
(new_string, number_of_subs_made).
|
||||||
|
|
||||||
|
@ -185,10 +185,10 @@ def subn(pattern, repl, string, count=0):
|
||||||
if type(pattern) == type(''):
|
if type(pattern) == type(''):
|
||||||
pattern = _cachecompile(pattern)
|
pattern = _cachecompile(pattern)
|
||||||
return pattern.subn(repl, string, count)
|
return pattern.subn(repl, string, count)
|
||||||
|
|
||||||
def split(pattern, string, maxsplit=0):
|
def split(pattern, string, maxsplit=0):
|
||||||
"""split(pattern, string[, maxsplit=0]) -> list of strings
|
"""split(pattern, string[, maxsplit=0]) -> list of strings
|
||||||
|
|
||||||
Split string by the occurrences of pattern. If capturing
|
Split string by the occurrences of pattern. If capturing
|
||||||
parentheses are used in pattern, then the text of all groups in
|
parentheses are used in pattern, then the text of all groups in
|
||||||
the pattern are also returned as part of the resulting list. If
|
the pattern are also returned as part of the resulting list. If
|
||||||
|
@ -203,7 +203,7 @@ def split(pattern, string, maxsplit=0):
|
||||||
|
|
||||||
def findall(pattern, string):
|
def findall(pattern, string):
|
||||||
"""findall(pattern, string) -> list
|
"""findall(pattern, string) -> list
|
||||||
|
|
||||||
Return a list of all non-overlapping matches of pattern in
|
Return a list of all non-overlapping matches of pattern in
|
||||||
string. If one or more groups are present in the pattern, return a
|
string. If one or more groups are present in the pattern, return a
|
||||||
list of groups; this will be a list of tuples if the pattern has
|
list of groups; this will be a list of tuples if the pattern has
|
||||||
|
@ -216,7 +216,7 @@ def findall(pattern, string):
|
||||||
|
|
||||||
def escape(pattern):
|
def escape(pattern):
|
||||||
"""escape(string) -> string
|
"""escape(string) -> string
|
||||||
|
|
||||||
Return string with all non-alphanumerics backslashed; this is
|
Return string with all non-alphanumerics backslashed; this is
|
||||||
useful if you want to match an arbitrary literal string that may
|
useful if you want to match an arbitrary literal string that may
|
||||||
have regular expression metacharacters in it.
|
have regular expression metacharacters in it.
|
||||||
|
@ -242,7 +242,7 @@ def compile(pattern, flags=0):
|
||||||
groupindex={}
|
groupindex={}
|
||||||
code=pcre_compile(pattern, flags, groupindex)
|
code=pcre_compile(pattern, flags, groupindex)
|
||||||
return RegexObject(pattern, flags, code, groupindex)
|
return RegexObject(pattern, flags, code, groupindex)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Class definitions
|
# Class definitions
|
||||||
|
@ -258,18 +258,18 @@ class RegexObject:
|
||||||
subn Same as sub, but also return the number of substitutions made.
|
subn Same as sub, but also return the number of substitutions made.
|
||||||
split Split a string by the occurrences of the pattern.
|
split Split a string by the occurrences of the pattern.
|
||||||
findall Find all occurrences of the pattern in a string.
|
findall Find all occurrences of the pattern in a string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, pattern, flags, code, groupindex):
|
def __init__(self, pattern, flags, code, groupindex):
|
||||||
self.code = code
|
self.code = code
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.pattern = pattern
|
self.pattern = pattern
|
||||||
self.groupindex = groupindex
|
self.groupindex = groupindex
|
||||||
|
|
||||||
def search(self, string, pos=0, endpos=None):
|
def search(self, string, pos=0, endpos=None):
|
||||||
"""search(string[, pos][, endpos]) -> MatchObject or None
|
"""search(string[, pos][, endpos]) -> MatchObject or None
|
||||||
|
|
||||||
Scan through string looking for a location where this regular
|
Scan through string looking for a location where this regular
|
||||||
expression produces a match, and return a corresponding
|
expression produces a match, and return a corresponding
|
||||||
MatchObject instance. Return None if no position in the string
|
MatchObject instance. Return None if no position in the string
|
||||||
|
@ -277,24 +277,24 @@ class RegexObject:
|
||||||
a zero-length match at some point in the string. The optional
|
a zero-length match at some point in the string. The optional
|
||||||
pos and endpos parameters have the same meaning as for the
|
pos and endpos parameters have the same meaning as for the
|
||||||
match() method.
|
match() method.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if endpos is None or endpos>len(string):
|
if endpos is None or endpos>len(string):
|
||||||
endpos=len(string)
|
endpos=len(string)
|
||||||
if endpos<pos: endpos=pos
|
if endpos<pos: endpos=pos
|
||||||
regs = self.code.match(string, pos, endpos, 0)
|
regs = self.code.match(string, pos, endpos, 0)
|
||||||
if regs is None:
|
if regs is None:
|
||||||
return None
|
return None
|
||||||
self._num_regs=len(regs)
|
self._num_regs=len(regs)
|
||||||
|
|
||||||
return MatchObject(self,
|
return MatchObject(self,
|
||||||
string,
|
string,
|
||||||
pos, endpos,
|
pos, endpos,
|
||||||
regs)
|
regs)
|
||||||
|
|
||||||
def match(self, string, pos=0, endpos=None):
|
def match(self, string, pos=0, endpos=None):
|
||||||
"""match(string[, pos][, endpos]) -> MatchObject or None
|
"""match(string[, pos][, endpos]) -> MatchObject or None
|
||||||
|
|
||||||
If zero or more characters at the beginning of string match
|
If zero or more characters at the beginning of string match
|
||||||
this regular expression, return a corresponding MatchObject
|
this regular expression, return a corresponding MatchObject
|
||||||
instance. Return None if the string does not match the
|
instance. Return None if the string does not match the
|
||||||
|
@ -316,7 +316,7 @@ class RegexObject:
|
||||||
searched for a match.
|
searched for a match.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if endpos is None or endpos>len(string):
|
if endpos is None or endpos>len(string):
|
||||||
endpos=len(string)
|
endpos=len(string)
|
||||||
if endpos<pos: endpos=pos
|
if endpos<pos: endpos=pos
|
||||||
regs = self.code.match(string, pos, endpos, ANCHORED)
|
regs = self.code.match(string, pos, endpos, ANCHORED)
|
||||||
|
@ -327,23 +327,23 @@ class RegexObject:
|
||||||
string,
|
string,
|
||||||
pos, endpos,
|
pos, endpos,
|
||||||
regs)
|
regs)
|
||||||
|
|
||||||
def sub(self, repl, string, count=0):
|
def sub(self, repl, string, count=0):
|
||||||
"""sub(repl, string[, count=0]) -> string
|
"""sub(repl, string[, count=0]) -> string
|
||||||
|
|
||||||
Return the string obtained by replacing the leftmost
|
Return the string obtained by replacing the leftmost
|
||||||
non-overlapping occurrences of the compiled pattern in string
|
non-overlapping occurrences of the compiled pattern in string
|
||||||
by the replacement repl. If the pattern isn't found, string is
|
by the replacement repl. If the pattern isn't found, string is
|
||||||
returned unchanged.
|
returned unchanged.
|
||||||
|
|
||||||
Identical to the sub() function, using the compiled pattern.
|
Identical to the sub() function, using the compiled pattern.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.subn(repl, string, count)[0]
|
return self.subn(repl, string, count)[0]
|
||||||
|
|
||||||
def subn(self, repl, source, count=0):
|
def subn(self, repl, source, count=0):
|
||||||
"""subn(repl, string[, count=0]) -> tuple
|
"""subn(repl, string[, count=0]) -> tuple
|
||||||
|
|
||||||
Perform the same operation as sub(), but return a tuple
|
Perform the same operation as sub(), but return a tuple
|
||||||
(new_string, number_of_subs_made).
|
(new_string, number_of_subs_made).
|
||||||
|
|
||||||
|
@ -399,17 +399,17 @@ class RegexObject:
|
||||||
n = n + 1
|
n = n + 1
|
||||||
append(source[pos:])
|
append(source[pos:])
|
||||||
return (string.join(results, ''), n)
|
return (string.join(results, ''), n)
|
||||||
|
|
||||||
def split(self, source, maxsplit=0):
|
def split(self, source, maxsplit=0):
|
||||||
"""split(source[, maxsplit=0]) -> list of strings
|
"""split(source[, maxsplit=0]) -> list of strings
|
||||||
|
|
||||||
Split string by the occurrences of the compiled pattern. If
|
Split string by the occurrences of the compiled pattern. If
|
||||||
capturing parentheses are used in the pattern, then the text
|
capturing parentheses are used in the pattern, then the text
|
||||||
of all groups in the pattern are also returned as part of the
|
of all groups in the pattern are also returned as part of the
|
||||||
resulting list. If maxsplit is nonzero, at most maxsplit
|
resulting list. If maxsplit is nonzero, at most maxsplit
|
||||||
splits occur, and the remainder of the string is returned as
|
splits occur, and the remainder of the string is returned as
|
||||||
the final element of the list.
|
the final element of the list.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if maxsplit < 0:
|
if maxsplit < 0:
|
||||||
raise error, "negative split count"
|
raise error, "negative split count"
|
||||||
|
@ -449,7 +449,7 @@ class RegexObject:
|
||||||
|
|
||||||
def findall(self, source):
|
def findall(self, source):
|
||||||
"""findall(source) -> list
|
"""findall(source) -> list
|
||||||
|
|
||||||
Return a list of all non-overlapping matches of the compiled
|
Return a list of all non-overlapping matches of the compiled
|
||||||
pattern in string. If one or more groups are present in the
|
pattern in string. If one or more groups are present in the
|
||||||
pattern, return a list of groups; this will be a list of
|
pattern, return a list of groups; this will be a list of
|
||||||
|
@ -487,7 +487,7 @@ class RegexObject:
|
||||||
def __getinitargs__(self):
|
def __getinitargs__(self):
|
||||||
return (None,None,None,None) # any 4 elements, to work around
|
return (None,None,None,None) # any 4 elements, to work around
|
||||||
# problems with the
|
# problems with the
|
||||||
# pickle/cPickle modules not yet
|
# pickle/cPickle modules not yet
|
||||||
# ignoring the __init__ function
|
# ignoring the __init__ function
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
return self.pattern, self.flags, self.groupindex
|
return self.pattern, self.flags, self.groupindex
|
||||||
|
@ -517,13 +517,13 @@ class MatchObject:
|
||||||
def __init__(self, re, string, pos, endpos, regs):
|
def __init__(self, re, string, pos, endpos, regs):
|
||||||
self.re = re
|
self.re = re
|
||||||
self.string = string
|
self.string = string
|
||||||
self.pos = pos
|
self.pos = pos
|
||||||
self.endpos = endpos
|
self.endpos = endpos
|
||||||
self.regs = regs
|
self.regs = regs
|
||||||
|
|
||||||
def start(self, g = 0):
|
def start(self, g = 0):
|
||||||
"""start([group=0]) -> int or None
|
"""start([group=0]) -> int or None
|
||||||
|
|
||||||
Return the index of the start of the substring matched by
|
Return the index of the start of the substring matched by
|
||||||
group; group defaults to zero (meaning the whole matched
|
group; group defaults to zero (meaning the whole matched
|
||||||
substring). Return -1 if group exists but did not contribute
|
substring). Return -1 if group exists but did not contribute
|
||||||
|
@ -536,10 +536,10 @@ class MatchObject:
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
raise IndexError, 'group %s is undefined' % `g`
|
raise IndexError, 'group %s is undefined' % `g`
|
||||||
return self.regs[g][0]
|
return self.regs[g][0]
|
||||||
|
|
||||||
def end(self, g = 0):
|
def end(self, g = 0):
|
||||||
"""end([group=0]) -> int or None
|
"""end([group=0]) -> int or None
|
||||||
|
|
||||||
Return the indices of the end of the substring matched by
|
Return the indices of the end of the substring matched by
|
||||||
group; group defaults to zero (meaning the whole matched
|
group; group defaults to zero (meaning the whole matched
|
||||||
substring). Return -1 if group exists but did not contribute
|
substring). Return -1 if group exists but did not contribute
|
||||||
|
@ -552,10 +552,10 @@ class MatchObject:
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
raise IndexError, 'group %s is undefined' % `g`
|
raise IndexError, 'group %s is undefined' % `g`
|
||||||
return self.regs[g][1]
|
return self.regs[g][1]
|
||||||
|
|
||||||
def span(self, g = 0):
|
def span(self, g = 0):
|
||||||
"""span([group=0]) -> tuple
|
"""span([group=0]) -> tuple
|
||||||
|
|
||||||
Return the 2-tuple (m.start(group), m.end(group)). Note that
|
Return the 2-tuple (m.start(group), m.end(group)). Note that
|
||||||
if group did not contribute to the match, this is (-1,
|
if group did not contribute to the match, this is (-1,
|
||||||
-1). Group defaults to zero (meaning the whole matched
|
-1). Group defaults to zero (meaning the whole matched
|
||||||
|
@ -568,10 +568,10 @@ class MatchObject:
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
raise IndexError, 'group %s is undefined' % `g`
|
raise IndexError, 'group %s is undefined' % `g`
|
||||||
return self.regs[g]
|
return self.regs[g]
|
||||||
|
|
||||||
def groups(self, default=None):
|
def groups(self, default=None):
|
||||||
"""groups([default=None]) -> tuple
|
"""groups([default=None]) -> tuple
|
||||||
|
|
||||||
Return a tuple containing all the subgroups of the match, from
|
Return a tuple containing all the subgroups of the match, from
|
||||||
1 up to however many groups are in the pattern. The default
|
1 up to however many groups are in the pattern. The default
|
||||||
argument is used for groups that did not participate in the
|
argument is used for groups that did not participate in the
|
||||||
|
@ -589,7 +589,7 @@ class MatchObject:
|
||||||
|
|
||||||
def group(self, *groups):
|
def group(self, *groups):
|
||||||
"""group([group1, group2, ...]) -> string or tuple
|
"""group([group1, group2, ...]) -> string or tuple
|
||||||
|
|
||||||
Return one or more subgroups of the match. If there is a
|
Return one or more subgroups of the match. If there is a
|
||||||
single argument, the result is a single string; if there are
|
single argument, the result is a single string; if there are
|
||||||
multiple arguments, the result is a tuple with one item per
|
multiple arguments, the result is a tuple with one item per
|
||||||
|
@ -636,7 +636,7 @@ class MatchObject:
|
||||||
|
|
||||||
def groupdict(self, default=None):
|
def groupdict(self, default=None):
|
||||||
"""groupdict([default=None]) -> dictionary
|
"""groupdict([default=None]) -> dictionary
|
||||||
|
|
||||||
Return a dictionary containing all the named subgroups of the
|
Return a dictionary containing all the named subgroups of the
|
||||||
match, keyed by the subgroup name. The default argument is
|
match, keyed by the subgroup name. The default argument is
|
||||||
used for groups that did not participate in the match.
|
used for groups that did not participate in the match.
|
||||||
|
|
858
Lib/profile.py
858
Lib/profile.py
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
# Copyright 1994, by InfoSeek Corporation, all rights reserved.
|
# Copyright 1994, by InfoSeek Corporation, all rights reserved.
|
||||||
# Written by James Roskind
|
# Written by James Roskind
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and distribute this Python software
|
# Permission to use, copy, modify, and distribute this Python software
|
||||||
# and its associated documentation for any purpose (subject to the
|
# and its associated documentation for any purpose (subject to the
|
||||||
# restriction in the following sentence) without fee is hereby granted,
|
# restriction in the following sentence) without fee is hereby granted,
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
# to remain in Python, compiled Python, or other languages (such as C)
|
# to remain in Python, compiled Python, or other languages (such as C)
|
||||||
# wherein the modified or derived code is exclusively imported into a
|
# wherein the modified or derived code is exclusively imported into a
|
||||||
# Python module.
|
# Python module.
|
||||||
#
|
#
|
||||||
# INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
# INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||||
# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
# FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY
|
# FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY
|
||||||
|
@ -41,12 +41,12 @@ import time
|
||||||
import marshal
|
import marshal
|
||||||
|
|
||||||
|
|
||||||
# Sample timer for use with
|
# Sample timer for use with
|
||||||
#i_count = 0
|
#i_count = 0
|
||||||
#def integer_timer():
|
#def integer_timer():
|
||||||
# global i_count
|
# global i_count
|
||||||
# i_count = i_count + 1
|
# i_count = i_count + 1
|
||||||
# return i_count
|
# return i_count
|
||||||
#itimes = integer_timer # replace with C coded timer returning integers
|
#itimes = integer_timer # replace with C coded timer returning integers
|
||||||
|
|
||||||
#**************************************************************************
|
#**************************************************************************
|
||||||
|
@ -57,515 +57,515 @@ import marshal
|
||||||
|
|
||||||
# simplified user interface
|
# simplified user interface
|
||||||
def run(statement, *args):
|
def run(statement, *args):
|
||||||
prof = Profile()
|
prof = Profile()
|
||||||
try:
|
try:
|
||||||
prof = prof.run(statement)
|
prof = prof.run(statement)
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
pass
|
pass
|
||||||
if args:
|
if args:
|
||||||
prof.dump_stats(args[0])
|
prof.dump_stats(args[0])
|
||||||
else:
|
else:
|
||||||
return prof.print_stats()
|
return prof.print_stats()
|
||||||
|
|
||||||
# print help
|
# print help
|
||||||
def help():
|
def help():
|
||||||
for dirname in sys.path:
|
for dirname in sys.path:
|
||||||
fullname = os.path.join(dirname, 'profile.doc')
|
fullname = os.path.join(dirname, 'profile.doc')
|
||||||
if os.path.exists(fullname):
|
if os.path.exists(fullname):
|
||||||
sts = os.system('${PAGER-more} '+fullname)
|
sts = os.system('${PAGER-more} '+fullname)
|
||||||
if sts: print '*** Pager exit status:', sts
|
if sts: print '*** Pager exit status:', sts
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print 'Sorry, can\'t find the help file "profile.doc"',
|
print 'Sorry, can\'t find the help file "profile.doc"',
|
||||||
print 'along the Python search path'
|
print 'along the Python search path'
|
||||||
|
|
||||||
|
|
||||||
class Profile:
|
class Profile:
|
||||||
"""Profiler class.
|
"""Profiler class.
|
||||||
|
|
||||||
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.
|
self.cur is always a tuple. Each such tuple corresponds to a stack
|
||||||
It is used so that a function call will not have to access the
|
frame that is currently active (self.cur[-2]). The following are the
|
||||||
timing data for the parent frame.
|
definitions of its members. We use this external "parallel stack" to
|
||||||
[ 1] = Total time spent in this frame's function, excluding time in
|
avoid contaminating the program that we are profiling. (old profiler
|
||||||
subfunctions
|
used to write into the frames local dictionary!!) Derived classes
|
||||||
[ 2] = Cumulative time spent in this frame's function, including time in
|
can change the definition of some entries, as long as they leave
|
||||||
all subfunctions to this frame.
|
[-2:] intact.
|
||||||
[-3] = Name of the function that corresponds to this frame.
|
|
||||||
[-2] = Actual frame that we correspond to (used to sync exception handling)
|
|
||||||
[-1] = Our parent 6-tuple (corresponds to frame.f_back)
|
|
||||||
|
|
||||||
Timing data for each function is stored as a 5-tuple in the dictionary
|
[ 0] = Time that needs to be charged to the parent frame's function.
|
||||||
self.timings[]. The index is always the name stored in self.cur[4].
|
It is used so that a function call will not have to access the
|
||||||
The following are the definitions of the members:
|
timing data for the parent 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 corresponds to this frame.
|
||||||
|
[-2] = Actual frame that we correspond to (used to sync exception handling)
|
||||||
|
[-1] = Our parent 6-tuple (corresponds to frame.f_back)
|
||||||
|
|
||||||
[0] = The number of times this function was called, not counting direct
|
Timing data for each function is stored as a 5-tuple in the dictionary
|
||||||
or indirect recursion,
|
self.timings[]. The index is always the name stored in self.cur[4].
|
||||||
[1] = Number of times this function appears on the stack, minus one
|
The following are the definitions of the members:
|
||||||
[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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, timer=None):
|
[0] = The number of times this function was called, not counting direct
|
||||||
self.timings = {}
|
or indirect recursion,
|
||||||
self.cur = None
|
[1] = Number of times this function appears on the stack, minus one
|
||||||
self.cmd = ""
|
[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.
|
||||||
|
"""
|
||||||
|
|
||||||
self.dispatch = { \
|
def __init__(self, timer=None):
|
||||||
'call' : self.trace_dispatch_call, \
|
self.timings = {}
|
||||||
'return' : self.trace_dispatch_return, \
|
self.cur = None
|
||||||
'exception': self.trace_dispatch_exception, \
|
self.cmd = ""
|
||||||
}
|
|
||||||
|
|
||||||
if not timer:
|
self.dispatch = { \
|
||||||
if os.name == 'mac':
|
'call' : self.trace_dispatch_call, \
|
||||||
import MacOS
|
'return' : self.trace_dispatch_return, \
|
||||||
self.timer = MacOS.GetTicks
|
'exception': self.trace_dispatch_exception, \
|
||||||
self.dispatcher = self.trace_dispatch_mac
|
}
|
||||||
self.get_time = self.get_time_mac
|
|
||||||
elif hasattr(time, 'clock'):
|
if not timer:
|
||||||
self.timer = time.clock
|
if os.name == 'mac':
|
||||||
self.dispatcher = self.trace_dispatch_i
|
import MacOS
|
||||||
elif hasattr(os, 'times'):
|
self.timer = MacOS.GetTicks
|
||||||
self.timer = os.times
|
self.dispatcher = self.trace_dispatch_mac
|
||||||
self.dispatcher = self.trace_dispatch
|
self.get_time = self.get_time_mac
|
||||||
else:
|
elif hasattr(time, 'clock'):
|
||||||
self.timer = time.time
|
self.timer = time.clock
|
||||||
self.dispatcher = self.trace_dispatch_i
|
self.dispatcher = self.trace_dispatch_i
|
||||||
else:
|
elif hasattr(os, 'times'):
|
||||||
self.timer = timer
|
self.timer = os.times
|
||||||
t = self.timer() # test out timer function
|
self.dispatcher = self.trace_dispatch
|
||||||
try:
|
else:
|
||||||
if len(t) == 2:
|
self.timer = time.time
|
||||||
self.dispatcher = self.trace_dispatch
|
self.dispatcher = self.trace_dispatch_i
|
||||||
else:
|
else:
|
||||||
self.dispatcher = self.trace_dispatch_l
|
self.timer = timer
|
||||||
except TypeError:
|
t = self.timer() # test out timer function
|
||||||
self.dispatcher = self.trace_dispatch_i
|
try:
|
||||||
self.t = self.get_time()
|
if len(t) == 2:
|
||||||
self.simulate_call('profiler')
|
self.dispatcher = self.trace_dispatch
|
||||||
|
else:
|
||||||
|
self.dispatcher = self.trace_dispatch_l
|
||||||
|
except TypeError:
|
||||||
|
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
|
def get_time(self): # slow simulation of method to acquire time
|
||||||
t = self.timer()
|
t = self.timer()
|
||||||
if type(t) == type(()) or type(t) == type([]):
|
if type(t) == type(()) or type(t) == type([]):
|
||||||
t = reduce(lambda x,y: x+y, t, 0)
|
t = reduce(lambda x,y: x+y, t, 0)
|
||||||
return t
|
return t
|
||||||
|
|
||||||
def get_time_mac(self):
|
|
||||||
return self.timer()/60.0
|
|
||||||
|
|
||||||
# Heavily optimized dispatch routine for os.times() timer
|
def get_time_mac(self):
|
||||||
|
return self.timer()/60.0
|
||||||
|
|
||||||
def trace_dispatch(self, frame, event, arg):
|
# Heavily optimized dispatch routine for os.times() timer
|
||||||
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):
|
def trace_dispatch(self, frame, event, arg):
|
||||||
t = self.timer()
|
t = self.timer()
|
||||||
self.t = t[0] + t[1]
|
t = t[0] + t[1] - self.t # No Calibration constant
|
||||||
else:
|
# t = t[0] + t[1] - self.t - .00053 # Calibration constant
|
||||||
r = self.timer()
|
|
||||||
self.t = r[0] + r[1] - t # put back unrecorded delta
|
if self.dispatch[event](frame,t):
|
||||||
return
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Dispatch routine for best timer program (return = scalar integer)
|
# Dispatch routine for best timer program (return = scalar integer)
|
||||||
|
|
||||||
def trace_dispatch_i(self, frame, event, arg):
|
def trace_dispatch_i(self, frame, event, arg):
|
||||||
t = self.timer() - self.t # - 1 # Integer calibration constant
|
t = self.timer() - self.t # - 1 # Integer calibration constant
|
||||||
if self.dispatch[event](frame,t):
|
if self.dispatch[event](frame,t):
|
||||||
self.t = self.timer()
|
self.t = self.timer()
|
||||||
else:
|
else:
|
||||||
self.t = self.timer() - t # put back unrecorded delta
|
self.t = self.timer() - t # put back unrecorded delta
|
||||||
return
|
return
|
||||||
|
|
||||||
# Dispatch routine for macintosh (timer returns time in ticks of 1/60th second)
|
|
||||||
|
|
||||||
def trace_dispatch_mac(self, frame, event, arg):
|
# Dispatch routine for macintosh (timer returns time in ticks of 1/60th second)
|
||||||
t = self.timer()/60.0 - self.t # - 1 # Integer calibration constant
|
|
||||||
if self.dispatch[event](frame,t):
|
def trace_dispatch_mac(self, frame, event, arg):
|
||||||
self.t = self.timer()/60.0
|
t = self.timer()/60.0 - self.t # - 1 # Integer calibration constant
|
||||||
else:
|
if self.dispatch[event](frame,t):
|
||||||
self.t = self.timer()/60.0 - t # put back unrecorded delta
|
self.t = self.timer()/60.0
|
||||||
return
|
else:
|
||||||
|
self.t = self.timer()/60.0 - t # put back unrecorded delta
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
# SLOW generic dispatch routine for timer returning lists of numbers
|
# SLOW generic dispatch routine for timer returning lists of numbers
|
||||||
|
|
||||||
def trace_dispatch_l(self, frame, event, arg):
|
def trace_dispatch_l(self, frame, event, arg):
|
||||||
t = self.get_time() - self.t
|
t = self.get_time() - self.t
|
||||||
|
|
||||||
if self.dispatch[event](frame,t):
|
if self.dispatch[event](frame,t):
|
||||||
self.t = self.get_time()
|
self.t = self.get_time()
|
||||||
else:
|
else:
|
||||||
self.t = self.get_time()-t # put back unrecorded delta
|
self.t = self.get_time()-t # put back unrecorded delta
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def trace_dispatch_exception(self, frame, t):
|
def trace_dispatch_exception(self, frame, t):
|
||||||
rt, rtt, rct, rfn, rframe, rcur = self.cur
|
rt, rtt, rct, rfn, rframe, rcur = self.cur
|
||||||
if (not rframe is frame) and rcur:
|
if (not rframe is frame) and rcur:
|
||||||
return self.trace_dispatch_return(rframe, t)
|
return self.trace_dispatch_return(rframe, t)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def trace_dispatch_call(self, frame, t):
|
def trace_dispatch_call(self, frame, t):
|
||||||
fcode = frame.f_code
|
fcode = frame.f_code
|
||||||
fn = (fcode.co_filename, fcode.co_firstlineno, fcode.co_name)
|
fn = (fcode.co_filename, fcode.co_firstlineno, fcode.co_name)
|
||||||
self.cur = (t, 0, 0, fn, frame, self.cur)
|
self.cur = (t, 0, 0, fn, frame, self.cur)
|
||||||
if self.timings.has_key(fn):
|
if self.timings.has_key(fn):
|
||||||
cc, ns, tt, ct, callers = self.timings[fn]
|
cc, ns, tt, ct, callers = self.timings[fn]
|
||||||
self.timings[fn] = cc, ns + 1, tt, ct, callers
|
self.timings[fn] = cc, ns + 1, tt, ct, callers
|
||||||
else:
|
else:
|
||||||
self.timings[fn] = 0, 0, 0, 0, {}
|
self.timings[fn] = 0, 0, 0, 0, {}
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def trace_dispatch_return(self, frame, t):
|
def trace_dispatch_return(self, frame, t):
|
||||||
# if not frame is self.cur[-2]: raise "Bad return", self.cur[3]
|
# if not frame is self.cur[-2]: raise "Bad return", self.cur[3]
|
||||||
|
|
||||||
# Prefix "r" means part of the Returning or exiting frame
|
# Prefix "r" means part of the Returning or exiting frame
|
||||||
# Prefix "p" means part of the Previous or older frame
|
# Prefix "p" means part of the Previous or older frame
|
||||||
|
|
||||||
rt, rtt, rct, rfn, frame, rcur = self.cur
|
rt, rtt, rct, rfn, frame, rcur = self.cur
|
||||||
rtt = rtt + t
|
rtt = rtt + t
|
||||||
sft = rtt + rct
|
sft = rtt + rct
|
||||||
|
|
||||||
pt, ptt, pct, pfn, pframe, pcur = rcur
|
pt, ptt, pct, pfn, pframe, pcur = rcur
|
||||||
self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur
|
self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur
|
||||||
|
|
||||||
cc, ns, tt, ct, callers = self.timings[rfn]
|
cc, ns, tt, ct, callers = self.timings[rfn]
|
||||||
if not ns:
|
if not ns:
|
||||||
ct = ct + sft
|
ct = ct + sft
|
||||||
cc = cc + 1
|
cc = cc + 1
|
||||||
if callers.has_key(pfn):
|
if callers.has_key(pfn):
|
||||||
callers[pfn] = callers[pfn] + 1 # hack: gather more
|
callers[pfn] = callers[pfn] + 1 # hack: gather more
|
||||||
# stats such as the amount of time added to ct courtesy
|
# stats such as the amount of time added to ct courtesy
|
||||||
# of this specific call, and the contribution to cc
|
# of this specific call, and the contribution to cc
|
||||||
# courtesy of this call.
|
# courtesy of this call.
|
||||||
else:
|
else:
|
||||||
callers[pfn] = 1
|
callers[pfn] = 1
|
||||||
self.timings[rfn] = cc, ns - 1, tt+rtt, ct, callers
|
self.timings[rfn] = cc, ns - 1, tt+rtt, ct, callers
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# The next few function play with self.cmd. By carefully preloading
|
# The next few function play with self.cmd. By carefully preloading
|
||||||
# our parallel stack, we can force the profiled result to include
|
# our parallel stack, we can force the profiled result to include
|
||||||
# an arbitrary string as the name of the calling function.
|
# an arbitrary string as the name of the calling function.
|
||||||
# We use self.cmd as that string, and the resulting stats look
|
# We use self.cmd as that string, and the resulting stats look
|
||||||
# very nice :-).
|
# very nice :-).
|
||||||
|
|
||||||
def set_cmd(self, cmd):
|
def set_cmd(self, cmd):
|
||||||
if self.cur[-1]: return # already set
|
if self.cur[-1]: return # already set
|
||||||
self.cmd = cmd
|
self.cmd = cmd
|
||||||
self.simulate_call(cmd)
|
self.simulate_call(cmd)
|
||||||
|
|
||||||
class fake_code:
|
class fake_code:
|
||||||
def __init__(self, filename, line, name):
|
def __init__(self, filename, line, name):
|
||||||
self.co_filename = filename
|
self.co_filename = filename
|
||||||
self.co_line = line
|
self.co_line = line
|
||||||
self.co_name = name
|
self.co_name = name
|
||||||
self.co_firstlineno = 0
|
self.co_firstlineno = 0
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return repr((self.co_filename, self.co_line, self.co_name))
|
return repr((self.co_filename, self.co_line, self.co_name))
|
||||||
|
|
||||||
class fake_frame:
|
class fake_frame:
|
||||||
def __init__(self, code, prior):
|
def __init__(self, code, prior):
|
||||||
self.f_code = code
|
self.f_code = code
|
||||||
self.f_back = prior
|
self.f_back = prior
|
||||||
|
|
||||||
def simulate_call(self, name):
|
|
||||||
code = self.fake_code('profile', 0, name)
|
|
||||||
if self.cur:
|
|
||||||
pframe = self.cur[-2]
|
|
||||||
else:
|
|
||||||
pframe = None
|
|
||||||
frame = self.fake_frame(code, pframe)
|
|
||||||
a = self.dispatch['call'](frame, 0)
|
|
||||||
return
|
|
||||||
|
|
||||||
# collect stats from pending stack, including getting final
|
def simulate_call(self, name):
|
||||||
# timings for self.cmd frame.
|
code = self.fake_code('profile', 0, name)
|
||||||
|
if self.cur:
|
||||||
def simulate_cmd_complete(self):
|
pframe = self.cur[-2]
|
||||||
t = self.get_time() - self.t
|
else:
|
||||||
while self.cur[-1]:
|
pframe = None
|
||||||
# We *can* cause assertion errors here if
|
frame = self.fake_frame(code, pframe)
|
||||||
# dispatch_trace_return checks for a frame match!
|
a = self.dispatch['call'](frame, 0)
|
||||||
a = self.dispatch['return'](self.cur[-2], t)
|
return
|
||||||
t = 0
|
|
||||||
self.t = self.get_time() - t
|
|
||||||
|
|
||||||
|
# collect stats from pending stack, including getting final
|
||||||
def print_stats(self):
|
# timings for self.cmd frame.
|
||||||
import pstats
|
|
||||||
pstats.Stats(self).strip_dirs().sort_stats(-1). \
|
|
||||||
print_stats()
|
|
||||||
|
|
||||||
def dump_stats(self, file):
|
def simulate_cmd_complete(self):
|
||||||
f = open(file, 'wb')
|
t = self.get_time() - self.t
|
||||||
self.create_stats()
|
while self.cur[-1]:
|
||||||
marshal.dump(self.stats, f)
|
# We *can* cause assertion errors here if
|
||||||
f.close()
|
# dispatch_trace_return checks for a frame match!
|
||||||
|
a = self.dispatch['return'](self.cur[-2], t)
|
||||||
def create_stats(self):
|
t = 0
|
||||||
self.simulate_cmd_complete()
|
self.t = self.get_time() - t
|
||||||
self.snapshot_stats()
|
|
||||||
|
|
||||||
def snapshot_stats(self):
|
|
||||||
self.stats = {}
|
|
||||||
for func in self.timings.keys():
|
|
||||||
cc, ns, tt, ct, callers = self.timings[func]
|
|
||||||
callers = callers.copy()
|
|
||||||
nc = 0
|
|
||||||
for func_caller in callers.keys():
|
|
||||||
nc = nc + callers[func_caller]
|
|
||||||
self.stats[func] = cc, nc, tt, ct, callers
|
|
||||||
|
|
||||||
|
|
||||||
# The following two methods can be called by clients to use
|
def print_stats(self):
|
||||||
# a profiler to profile a statement, given as a string.
|
import pstats
|
||||||
|
pstats.Stats(self).strip_dirs().sort_stats(-1). \
|
||||||
def run(self, cmd):
|
print_stats()
|
||||||
import __main__
|
|
||||||
dict = __main__.__dict__
|
|
||||||
return self.runctx(cmd, dict, dict)
|
|
||||||
|
|
||||||
def runctx(self, cmd, globals, locals):
|
|
||||||
self.set_cmd(cmd)
|
|
||||||
sys.setprofile(self.dispatcher)
|
|
||||||
try:
|
|
||||||
exec cmd in globals, locals
|
|
||||||
finally:
|
|
||||||
sys.setprofile(None)
|
|
||||||
return self
|
|
||||||
|
|
||||||
# This method is more useful to profile a single function call.
|
def dump_stats(self, file):
|
||||||
def runcall(self, func, *args):
|
f = open(file, 'wb')
|
||||||
self.set_cmd(`func`)
|
self.create_stats()
|
||||||
sys.setprofile(self.dispatcher)
|
marshal.dump(self.stats, f)
|
||||||
try:
|
f.close()
|
||||||
return apply(func, args)
|
|
||||||
finally:
|
def create_stats(self):
|
||||||
sys.setprofile(None)
|
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]
|
||||||
|
callers = callers.copy()
|
||||||
|
nc = 0
|
||||||
|
for func_caller in callers.keys():
|
||||||
|
nc = nc + callers[func_caller]
|
||||||
|
self.stats[func] = cc, nc, tt, ct, callers
|
||||||
|
|
||||||
|
|
||||||
#******************************************************************
|
# The following two methods can be called by clients to use
|
||||||
# The following calculates the overhead for using a profiler. The
|
# a profiler to profile a statement, given as a string.
|
||||||
# problem is that it takes a fair amount of time for the profiler
|
|
||||||
# to stop the stopwatch (from the time it receives 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). Currently, 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):
|
|
||||||
# Modified by Tim Peters
|
|
||||||
n = m
|
|
||||||
s = self.get_time()
|
|
||||||
while n:
|
|
||||||
self.simple()
|
|
||||||
n = n - 1
|
|
||||||
f = self.get_time()
|
|
||||||
my_simple = f - s
|
|
||||||
#print "Simple =", my_simple,
|
|
||||||
|
|
||||||
n = m
|
def run(self, cmd):
|
||||||
s = self.get_time()
|
import __main__
|
||||||
while n:
|
dict = __main__.__dict__
|
||||||
self.instrumented()
|
return self.runctx(cmd, dict, dict)
|
||||||
n = n - 1
|
|
||||||
f = self.get_time()
|
|
||||||
my_inst = f - s
|
|
||||||
# print "Instrumented =", my_inst
|
|
||||||
avg_cost = (my_inst - my_simple)/m
|
|
||||||
#print "Delta/call =", avg_cost, "(profiler fixup constant)"
|
|
||||||
return avg_cost
|
|
||||||
|
|
||||||
# simulate a program with no profiler activity
|
def runctx(self, cmd, globals, locals):
|
||||||
def simple(self):
|
self.set_cmd(cmd)
|
||||||
a = 1
|
sys.setprofile(self.dispatcher)
|
||||||
pass
|
try:
|
||||||
|
exec cmd in globals, locals
|
||||||
|
finally:
|
||||||
|
sys.setprofile(None)
|
||||||
|
return self
|
||||||
|
|
||||||
# simulate a program with call/return event processing
|
# This method is more useful to profile a single function call.
|
||||||
def instrumented(self):
|
def runcall(self, func, *args):
|
||||||
a = 1
|
self.set_cmd(`func`)
|
||||||
self.profiler_simulation(a, a, a)
|
sys.setprofile(self.dispatcher)
|
||||||
|
try:
|
||||||
|
return apply(func, args)
|
||||||
|
finally:
|
||||||
|
sys.setprofile(None)
|
||||||
|
|
||||||
# simulate an event processing activity (from user's perspective)
|
|
||||||
def profiler_simulation(self, x, y, z):
|
#******************************************************************
|
||||||
t = self.timer()
|
# The following calculates the overhead for using a profiler. The
|
||||||
## t = t[0] + t[1]
|
# problem is that it takes a fair amount of time for the profiler
|
||||||
self.ut = t
|
# to stop the stopwatch (from the time it receives 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). Currently, 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):
|
||||||
|
# Modified by Tim Peters
|
||||||
|
n = m
|
||||||
|
s = self.get_time()
|
||||||
|
while n:
|
||||||
|
self.simple()
|
||||||
|
n = n - 1
|
||||||
|
f = self.get_time()
|
||||||
|
my_simple = f - s
|
||||||
|
#print "Simple =", my_simple,
|
||||||
|
|
||||||
|
n = m
|
||||||
|
s = self.get_time()
|
||||||
|
while n:
|
||||||
|
self.instrumented()
|
||||||
|
n = n - 1
|
||||||
|
f = self.get_time()
|
||||||
|
my_inst = f - s
|
||||||
|
# print "Instrumented =", my_inst
|
||||||
|
avg_cost = (my_inst - my_simple)/m
|
||||||
|
#print "Delta/call =", avg_cost, "(profiler fixup constant)"
|
||||||
|
return avg_cost
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class OldProfile(Profile):
|
class OldProfile(Profile):
|
||||||
"""A derived profiler that simulates the old style profile, providing
|
"""A derived profiler that simulates the old style profile, providing
|
||||||
errant results on recursive functions. The reason for the usefulness of
|
errant results on recursive functions. The reason for the usefulness of
|
||||||
this profiler is that it runs faster (i.e., less overhead). It still
|
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*
|
creates all the caller stats, and is quite useful when there is *no*
|
||||||
recursion in the user's code.
|
recursion in the user's code.
|
||||||
|
|
||||||
This code also shows how easy it is to create a modified profiler.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def trace_dispatch_exception(self, frame, t):
|
This code also shows how easy it is to create a modified profiler.
|
||||||
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):
|
def trace_dispatch_exception(self, frame, t):
|
||||||
fn = `frame.f_code`
|
rt, rtt, rct, rfn, rframe, rcur = self.cur
|
||||||
|
if rcur and not rframe is frame:
|
||||||
self.cur = (t, 0, 0, fn, frame, self.cur)
|
return self.trace_dispatch_return(rframe, t)
|
||||||
if self.timings.has_key(fn):
|
return 0
|
||||||
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):
|
def trace_dispatch_call(self, frame, t):
|
||||||
rt, rtt, rct, rfn, frame, rcur = self.cur
|
fn = `frame.f_code`
|
||||||
rtt = rtt + t
|
|
||||||
sft = rtt + rct
|
|
||||||
|
|
||||||
pt, ptt, pct, pfn, pframe, pcur = rcur
|
self.cur = (t, 0, 0, fn, frame, self.cur)
|
||||||
self.cur = pt, ptt+rt, pct+sft, pfn, pframe, pcur
|
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
|
||||||
|
|
||||||
tt, ct, callers = self.timings[rfn]
|
def trace_dispatch_return(self, frame, t):
|
||||||
if callers.has_key(pfn):
|
rt, rtt, rct, rfn, frame, rcur = self.cur
|
||||||
callers[pfn] = callers[pfn] + 1
|
rtt = rtt + t
|
||||||
else:
|
sft = rtt + rct
|
||||||
callers[pfn] = 1
|
|
||||||
self.timings[rfn] = tt+rtt, ct + sft, callers
|
|
||||||
|
|
||||||
return 1
|
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):
|
def snapshot_stats(self):
|
||||||
self.stats = {}
|
self.stats = {}
|
||||||
for func in self.timings.keys():
|
for func in self.timings.keys():
|
||||||
tt, ct, callers = self.timings[func]
|
tt, ct, callers = self.timings[func]
|
||||||
callers = callers.copy()
|
callers = callers.copy()
|
||||||
nc = 0
|
nc = 0
|
||||||
for func_caller in callers.keys():
|
for func_caller in callers.keys():
|
||||||
nc = nc + callers[func_caller]
|
nc = nc + callers[func_caller]
|
||||||
self.stats[func] = nc, nc, tt, ct, callers
|
self.stats[func] = nc, nc, tt, ct, callers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class HotProfile(Profile):
|
class HotProfile(Profile):
|
||||||
"""The fastest derived profile example. It does not calculate
|
"""The fastest derived profile example. It does not calculate
|
||||||
caller-callee relationships, and does not calculate cumulative
|
caller-callee relationships, and does not calculate cumulative
|
||||||
time under a function. It only calculates time spent in a
|
time under a function. It only calculates time spent in a
|
||||||
function, so it runs very quickly due to its very low overhead.
|
function, so it runs very quickly due to its very low overhead.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def trace_dispatch_exception(self, frame, t):
|
def trace_dispatch_exception(self, frame, t):
|
||||||
rt, rtt, rfn, rframe, rcur = self.cur
|
rt, rtt, rfn, rframe, rcur = self.cur
|
||||||
if rcur and not rframe is frame:
|
if rcur and not rframe is frame:
|
||||||
return self.trace_dispatch_return(rframe, t)
|
return self.trace_dispatch_return(rframe, t)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def trace_dispatch_call(self, frame, t):
|
def trace_dispatch_call(self, frame, t):
|
||||||
self.cur = (t, 0, frame, self.cur)
|
self.cur = (t, 0, frame, self.cur)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def trace_dispatch_return(self, frame, t):
|
def trace_dispatch_return(self, frame, t):
|
||||||
rt, rtt, frame, rcur = self.cur
|
rt, rtt, frame, rcur = self.cur
|
||||||
|
|
||||||
rfn = `frame.f_code`
|
rfn = `frame.f_code`
|
||||||
|
|
||||||
pt, ptt, pframe, pcur = rcur
|
pt, ptt, pframe, pcur = rcur
|
||||||
self.cur = pt, ptt+rt, pframe, pcur
|
self.cur = pt, ptt+rt, pframe, pcur
|
||||||
|
|
||||||
if self.timings.has_key(rfn):
|
if self.timings.has_key(rfn):
|
||||||
nc, tt = self.timings[rfn]
|
nc, tt = self.timings[rfn]
|
||||||
self.timings[rfn] = nc + 1, rt + rtt + tt
|
self.timings[rfn] = nc + 1, rt + rtt + tt
|
||||||
else:
|
else:
|
||||||
self.timings[rfn] = 1, rt + rtt
|
self.timings[rfn] = 1, rt + rtt
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def snapshot_stats(self):
|
def snapshot_stats(self):
|
||||||
self.stats = {}
|
self.stats = {}
|
||||||
for func in self.timings.keys():
|
for func in self.timings.keys():
|
||||||
nc, tt = self.timings[func]
|
nc, tt = self.timings[func]
|
||||||
self.stats[func] = nc, nc, tt, 0, {}
|
self.stats[func] = nc, nc, tt, 0, {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#****************************************************************************
|
#****************************************************************************
|
||||||
def Stats(*args):
|
def Stats(*args):
|
||||||
print 'Report generating functions are in the "pstats" module\a'
|
print 'Report generating functions are in the "pstats" module\a'
|
||||||
|
|
||||||
|
|
||||||
# When invoked as main program, invoke the profiler on a script
|
# When invoked as main program, invoke the profiler on a script
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
if not sys.argv[1:]:
|
if not sys.argv[1:]:
|
||||||
print "usage: profile.py scriptfile [arg] ..."
|
print "usage: profile.py scriptfile [arg] ..."
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
filename = sys.argv[1] # Get script filename
|
filename = sys.argv[1] # Get script filename
|
||||||
|
|
||||||
del sys.argv[0] # Hide "profile.py" from argument list
|
del sys.argv[0] # Hide "profile.py" from argument list
|
||||||
|
|
||||||
# Insert script directory in front of module search path
|
# Insert script directory in front of module search path
|
||||||
sys.path.insert(0, os.path.dirname(filename))
|
sys.path.insert(0, os.path.dirname(filename))
|
||||||
|
|
||||||
run('execfile(' + `filename` + ')')
|
run('execfile(' + `filename` + ')')
|
||||||
|
|
839
Lib/pstats.py
839
Lib/pstats.py
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
# Copyright 1994, by InfoSeek Corporation, all rights reserved.
|
# Copyright 1994, by InfoSeek Corporation, all rights reserved.
|
||||||
# Written by James Roskind
|
# Written by James Roskind
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and distribute this Python software
|
# Permission to use, copy, modify, and distribute this Python software
|
||||||
# and its associated documentation for any purpose (subject to the
|
# and its associated documentation for any purpose (subject to the
|
||||||
# restriction in the following sentence) without fee is hereby granted,
|
# restriction in the following sentence) without fee is hereby granted,
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
# to remain in Python, compiled Python, or other languages (such as C)
|
# to remain in Python, compiled Python, or other languages (such as C)
|
||||||
# wherein the modified or derived code is exclusively imported into a
|
# wherein the modified or derived code is exclusively imported into a
|
||||||
# Python module.
|
# Python module.
|
||||||
#
|
#
|
||||||
# INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
# INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||||
# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
# FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY
|
# FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY
|
||||||
|
@ -41,486 +41,485 @@ import re
|
||||||
import fpformat
|
import fpformat
|
||||||
|
|
||||||
class Stats:
|
class Stats:
|
||||||
"""This class is used for creating reports from data generated by the
|
"""This class is used for creating reports from data generated by the
|
||||||
Profile class. It is a "friend" of that class, and imports data either
|
Profile class. It is a "friend" of that class, and imports data either
|
||||||
by direct access to members of Profile class, or by reading in a dictionary
|
by direct access to members of Profile class, or by reading in a dictionary
|
||||||
that was emitted (via marshal) from the Profile class.
|
that was emitted (via marshal) from the Profile class.
|
||||||
|
|
||||||
The big change from the previous Profiler (in terms of raw functionality)
|
The big change from the previous Profiler (in terms of raw functionality)
|
||||||
is that an "add()" method has been provided to combine Stats from
|
is that an "add()" method has been provided to combine Stats from
|
||||||
several distinct profile runs. Both the constructor and the add()
|
several distinct profile runs. Both the constructor and the add()
|
||||||
method now take arbitrarily many file names as arguments.
|
method now take arbitrarily many file names as arguments.
|
||||||
|
|
||||||
All the print methods now take an argument that indicates how many lines
|
All the print methods now take an argument that indicates how many lines
|
||||||
to print. If the arg is a floating point number between 0 and 1.0, then
|
to print. If the arg is a floating point number between 0 and 1.0, then
|
||||||
it is taken as a decimal percentage of the available lines to be printed
|
it is taken as a decimal percentage of the available lines to be printed
|
||||||
(e.g., .1 means print 10% of all available lines). If it is an integer,
|
(e.g., .1 means print 10% of all available lines). If it is an integer,
|
||||||
it is taken to mean the number of lines of data that you wish to have
|
it is taken to mean the number of lines of data that you wish to have
|
||||||
printed.
|
printed.
|
||||||
|
|
||||||
The sort_stats() method now processes some additional options (i.e., in
|
The sort_stats() method now processes some additional options (i.e., in
|
||||||
addition to the old -1, 0, 1, or 2). It takes an arbitrary number of quoted
|
addition to the old -1, 0, 1, or 2). It takes an arbitrary number of quoted
|
||||||
strings to select the sort order. For example sort_stats('time', 'name')
|
strings to select the sort order. For example sort_stats('time', 'name')
|
||||||
sorts on the major key of "internal function time", and on the minor
|
sorts on the major key of "internal function time", and on the minor
|
||||||
key of 'the name of the function'. Look at the two tables in sort_stats()
|
key of 'the name of the function'. Look at the two tables in sort_stats()
|
||||||
and get_sort_arg_defs(self) for more examples.
|
and get_sort_arg_defs(self) for more examples.
|
||||||
|
|
||||||
All methods now return "self", so you can string together commands like:
|
All methods now return "self", so you can string together commands like:
|
||||||
Stats('foo', 'goo').strip_dirs().sort_stats('calls').\
|
Stats('foo', 'goo').strip_dirs().sort_stats('calls').\
|
||||||
print_stats(5).print_callers(5)
|
print_stats(5).print_callers(5)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
if not len(args):
|
if not len(args):
|
||||||
arg = None
|
arg = None
|
||||||
else:
|
else:
|
||||||
arg = args[0]
|
arg = args[0]
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
self.init(arg)
|
self.init(arg)
|
||||||
apply(self.add, args).ignore()
|
apply(self.add, args).ignore()
|
||||||
|
|
||||||
def init(self, arg):
|
def init(self, arg):
|
||||||
self.all_callees = None # calc only if needed
|
self.all_callees = None # calc only if needed
|
||||||
self.files = []
|
self.files = []
|
||||||
self.fcn_list = None
|
self.fcn_list = None
|
||||||
self.total_tt = 0
|
self.total_tt = 0
|
||||||
self.total_calls = 0
|
self.total_calls = 0
|
||||||
self.prim_calls = 0
|
self.prim_calls = 0
|
||||||
self.max_name_len = 0
|
self.max_name_len = 0
|
||||||
self.top_level = {}
|
self.top_level = {}
|
||||||
self.stats = {}
|
self.stats = {}
|
||||||
self.sort_arg_dict = {}
|
self.sort_arg_dict = {}
|
||||||
self.load_stats(arg)
|
self.load_stats(arg)
|
||||||
trouble = 1
|
trouble = 1
|
||||||
try:
|
try:
|
||||||
self.get_top_level_stats()
|
self.get_top_level_stats()
|
||||||
trouble = 0
|
trouble = 0
|
||||||
finally:
|
finally:
|
||||||
if trouble:
|
if trouble:
|
||||||
print "Invalid timing data",
|
print "Invalid timing data",
|
||||||
if self.files: print self.files[-1],
|
if self.files: print self.files[-1],
|
||||||
print
|
print
|
||||||
|
|
||||||
|
|
||||||
def load_stats(self, arg):
|
def load_stats(self, arg):
|
||||||
if not arg: self.stats = {}
|
if not arg: self.stats = {}
|
||||||
elif type(arg) == type(""):
|
elif type(arg) == type(""):
|
||||||
f = open(arg, 'rb')
|
f = open(arg, 'rb')
|
||||||
self.stats = marshal.load(f)
|
self.stats = marshal.load(f)
|
||||||
f.close()
|
f.close()
|
||||||
try:
|
try:
|
||||||
file_stats = os.stat(arg)
|
file_stats = os.stat(arg)
|
||||||
arg = time.ctime(file_stats[8]) + " " + arg
|
arg = time.ctime(file_stats[8]) + " " + arg
|
||||||
except: # in case this is not unix
|
except: # in case this is not unix
|
||||||
pass
|
pass
|
||||||
self.files = [ arg ]
|
self.files = [ arg ]
|
||||||
elif hasattr(arg, 'create_stats'):
|
elif hasattr(arg, 'create_stats'):
|
||||||
arg.create_stats()
|
arg.create_stats()
|
||||||
self.stats = arg.stats
|
self.stats = arg.stats
|
||||||
arg.stats = {}
|
arg.stats = {}
|
||||||
if not self.stats:
|
if not self.stats:
|
||||||
raise TypeError, "Cannot create or construct a " \
|
raise TypeError, "Cannot create or construct a " \
|
||||||
+ `self.__class__` \
|
+ `self.__class__` \
|
||||||
+ " object from '" + `arg` + "'"
|
+ " object from '" + `arg` + "'"
|
||||||
return
|
return
|
||||||
|
|
||||||
def get_top_level_stats(self):
|
def get_top_level_stats(self):
|
||||||
for func in self.stats.keys():
|
for func in self.stats.keys():
|
||||||
cc, nc, tt, ct, callers = self.stats[func]
|
cc, nc, tt, ct, callers = self.stats[func]
|
||||||
self.total_calls = self.total_calls + nc
|
self.total_calls = self.total_calls + nc
|
||||||
self.prim_calls = self.prim_calls + cc
|
self.prim_calls = self.prim_calls + cc
|
||||||
self.total_tt = self.total_tt + tt
|
self.total_tt = self.total_tt + tt
|
||||||
if callers.has_key(("jprofile", 0, "profiler")):
|
if callers.has_key(("jprofile", 0, "profiler")):
|
||||||
self.top_level[func] = None
|
self.top_level[func] = None
|
||||||
if len(func_std_string(func)) > self.max_name_len:
|
if len(func_std_string(func)) > self.max_name_len:
|
||||||
self.max_name_len = len(func_std_string(func))
|
self.max_name_len = len(func_std_string(func))
|
||||||
|
|
||||||
def add(self, *arg_list):
|
|
||||||
if not arg_list: return self
|
|
||||||
if len(arg_list) > 1: apply(self.add, arg_list[1:])
|
|
||||||
other = arg_list[0]
|
|
||||||
if type(self) != type(other) or \
|
|
||||||
self.__class__ != other.__class__:
|
|
||||||
other = Stats(other)
|
|
||||||
self.files = self.files + other.files
|
|
||||||
self.total_calls = self.total_calls + other.total_calls
|
|
||||||
self.prim_calls = self.prim_calls + other.prim_calls
|
|
||||||
self.total_tt = self.total_tt + other.total_tt
|
|
||||||
for func in other.top_level.keys():
|
|
||||||
self.top_level[func] = None
|
|
||||||
|
|
||||||
if self.max_name_len < other.max_name_len:
|
def add(self, *arg_list):
|
||||||
self.max_name_len = other.max_name_len
|
if not arg_list: return self
|
||||||
|
if len(arg_list) > 1: apply(self.add, arg_list[1:])
|
||||||
|
other = arg_list[0]
|
||||||
|
if type(self) != type(other) or \
|
||||||
|
self.__class__ != other.__class__:
|
||||||
|
other = Stats(other)
|
||||||
|
self.files = self.files + other.files
|
||||||
|
self.total_calls = self.total_calls + other.total_calls
|
||||||
|
self.prim_calls = self.prim_calls + other.prim_calls
|
||||||
|
self.total_tt = self.total_tt + other.total_tt
|
||||||
|
for func in other.top_level.keys():
|
||||||
|
self.top_level[func] = None
|
||||||
|
|
||||||
self.fcn_list = None
|
if self.max_name_len < other.max_name_len:
|
||||||
|
self.max_name_len = other.max_name_len
|
||||||
|
|
||||||
for func in other.stats.keys():
|
self.fcn_list = None
|
||||||
if self.stats.has_key(func):
|
|
||||||
old_func_stat = self.stats[func]
|
|
||||||
else:
|
|
||||||
old_func_stat = (0, 0, 0, 0, {},)
|
|
||||||
self.stats[func] = add_func_stats(old_func_stat, \
|
|
||||||
other.stats[func])
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
|
for func in other.stats.keys():
|
||||||
# list the tuple indices and directions for sorting,
|
if self.stats.has_key(func):
|
||||||
# along with some printable description
|
old_func_stat = self.stats[func]
|
||||||
sort_arg_dict_default = {\
|
else:
|
||||||
"calls" : (((1,-1), ), "call count"),\
|
old_func_stat = (0, 0, 0, 0, {},)
|
||||||
"cumulative": (((3,-1), ), "cumulative time"),\
|
self.stats[func] = add_func_stats(old_func_stat, \
|
||||||
"file" : (((4, 1), ), "file name"),\
|
other.stats[func])
|
||||||
"line" : (((5, 1), ), "line number"),\
|
return self
|
||||||
"module" : (((4, 1), ), "file name"),\
|
|
||||||
"name" : (((6, 1), ), "function name"),\
|
|
||||||
"nfl" : (((6, 1),(4, 1),(5, 1),), "name/file/line"), \
|
|
||||||
"pcalls" : (((0,-1), ), "call count"),\
|
|
||||||
"stdname" : (((7, 1), ), "standard name"),\
|
|
||||||
"time" : (((2,-1), ), "internal time"),\
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_sort_arg_defs(self):
|
|
||||||
"""Expand all abbreviations that are unique."""
|
|
||||||
if not self.sort_arg_dict:
|
|
||||||
self.sort_arg_dict = dict = {}
|
|
||||||
std_list = dict.keys()
|
|
||||||
bad_list = {}
|
|
||||||
for word in self.sort_arg_dict_default.keys():
|
|
||||||
fragment = word
|
|
||||||
while fragment:
|
|
||||||
if not fragment:
|
|
||||||
break
|
|
||||||
if dict.has_key(fragment):
|
|
||||||
bad_list[fragment] = 0
|
|
||||||
break
|
|
||||||
dict[fragment] = self. \
|
|
||||||
sort_arg_dict_default[word]
|
|
||||||
fragment = fragment[:-1]
|
|
||||||
for word in bad_list.keys():
|
|
||||||
del dict[word]
|
|
||||||
return self.sort_arg_dict
|
|
||||||
|
|
||||||
|
|
||||||
def sort_stats(self, *field):
|
|
||||||
if not field:
|
|
||||||
self.fcn_list = 0
|
|
||||||
return self
|
|
||||||
if len(field) == 1 and type(field[0]) == type(1):
|
|
||||||
# Be compatible with old profiler
|
|
||||||
field = [ {-1: "stdname", \
|
|
||||||
0:"calls", \
|
|
||||||
1:"time", \
|
|
||||||
2: "cumulative" } [ field[0] ] ]
|
|
||||||
|
|
||||||
sort_arg_defs = self.get_sort_arg_defs()
|
|
||||||
sort_tuple = ()
|
|
||||||
self.sort_type = ""
|
|
||||||
connector = ""
|
|
||||||
for word in field:
|
|
||||||
sort_tuple = sort_tuple + sort_arg_defs[word][0]
|
|
||||||
self.sort_type = self.sort_type + connector + \
|
|
||||||
sort_arg_defs[word][1]
|
|
||||||
connector = ", "
|
|
||||||
|
|
||||||
stats_list = []
|
|
||||||
for func in self.stats.keys():
|
|
||||||
cc, nc, tt, ct, callers = self.stats[func]
|
|
||||||
stats_list.append((cc, nc, tt, ct) + func_split(func) \
|
|
||||||
+ (func_std_string(func), func,) )
|
|
||||||
|
|
||||||
stats_list.sort(TupleComp(sort_tuple).compare)
|
|
||||||
|
|
||||||
self.fcn_list = fcn_list = []
|
|
||||||
for tuple in stats_list:
|
|
||||||
fcn_list.append(tuple[-1])
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
def reverse_order(self):
|
|
||||||
if self.fcn_list: self.fcn_list.reverse()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def strip_dirs(self):
|
|
||||||
oldstats = self.stats
|
|
||||||
self.stats = newstats = {}
|
|
||||||
max_name_len = 0
|
|
||||||
for func in oldstats.keys():
|
|
||||||
cc, nc, tt, ct, callers = oldstats[func]
|
|
||||||
newfunc = func_strip_path(func)
|
|
||||||
if len(func_std_string(newfunc)) > max_name_len:
|
|
||||||
max_name_len = len(func_std_string(newfunc))
|
|
||||||
newcallers = {}
|
|
||||||
for func2 in callers.keys():
|
|
||||||
newcallers[func_strip_path(func2)] = \
|
|
||||||
callers[func2]
|
|
||||||
|
|
||||||
if newstats.has_key(newfunc):
|
|
||||||
newstats[newfunc] = add_func_stats( \
|
|
||||||
newstats[newfunc],\
|
|
||||||
(cc, nc, tt, ct, newcallers))
|
|
||||||
else:
|
|
||||||
newstats[newfunc] = (cc, nc, tt, ct, newcallers)
|
|
||||||
old_top = self.top_level
|
|
||||||
self.top_level = new_top = {}
|
|
||||||
for func in old_top.keys():
|
|
||||||
new_top[func_strip_path(func)] = None
|
|
||||||
|
|
||||||
self.max_name_len = max_name_len
|
|
||||||
|
|
||||||
self.fcn_list = None
|
|
||||||
self.all_callees = None
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def calc_callees(self):
|
# list the tuple indices and directions for sorting,
|
||||||
if self.all_callees: return
|
# along with some printable description
|
||||||
self.all_callees = all_callees = {}
|
sort_arg_dict_default = {\
|
||||||
for func in self.stats.keys():
|
"calls" : (((1,-1), ), "call count"),\
|
||||||
if not all_callees.has_key(func):
|
"cumulative": (((3,-1), ), "cumulative time"),\
|
||||||
all_callees[func] = {}
|
"file" : (((4, 1), ), "file name"),\
|
||||||
cc, nc, tt, ct, callers = self.stats[func]
|
"line" : (((5, 1), ), "line number"),\
|
||||||
for func2 in callers.keys():
|
"module" : (((4, 1), ), "file name"),\
|
||||||
if not all_callees.has_key(func2):
|
"name" : (((6, 1), ), "function name"),\
|
||||||
all_callees[func2] = {}
|
"nfl" : (((6, 1),(4, 1),(5, 1),), "name/file/line"), \
|
||||||
all_callees[func2][func] = callers[func2]
|
"pcalls" : (((0,-1), ), "call count"),\
|
||||||
return
|
"stdname" : (((7, 1), ), "standard name"),\
|
||||||
|
"time" : (((2,-1), ), "internal time"),\
|
||||||
|
}
|
||||||
|
|
||||||
#******************************************************************
|
def get_sort_arg_defs(self):
|
||||||
# The following functions support actual printing of reports
|
"""Expand all abbreviations that are unique."""
|
||||||
#******************************************************************
|
if not self.sort_arg_dict:
|
||||||
|
self.sort_arg_dict = dict = {}
|
||||||
|
std_list = dict.keys()
|
||||||
|
bad_list = {}
|
||||||
|
for word in self.sort_arg_dict_default.keys():
|
||||||
|
fragment = word
|
||||||
|
while fragment:
|
||||||
|
if not fragment:
|
||||||
|
break
|
||||||
|
if dict.has_key(fragment):
|
||||||
|
bad_list[fragment] = 0
|
||||||
|
break
|
||||||
|
dict[fragment] = self. \
|
||||||
|
sort_arg_dict_default[word]
|
||||||
|
fragment = fragment[:-1]
|
||||||
|
for word in bad_list.keys():
|
||||||
|
del dict[word]
|
||||||
|
return self.sort_arg_dict
|
||||||
|
|
||||||
# Optional "amount" is either a line count, or a percentage of lines.
|
|
||||||
|
|
||||||
def eval_print_amount(self, sel, list, msg):
|
def sort_stats(self, *field):
|
||||||
new_list = list
|
if not field:
|
||||||
if type(sel) == type(""):
|
self.fcn_list = 0
|
||||||
new_list = []
|
return self
|
||||||
for func in list:
|
if len(field) == 1 and type(field[0]) == type(1):
|
||||||
if re.search(sel, func_std_string(func)):
|
# Be compatible with old profiler
|
||||||
new_list.append(func)
|
field = [ {-1: "stdname", \
|
||||||
else:
|
0:"calls", \
|
||||||
count = len(list)
|
1:"time", \
|
||||||
if type(sel) == type(1.0) and 0.0 <= sel < 1.0:
|
2: "cumulative" } [ field[0] ] ]
|
||||||
count = int (count * sel + .5)
|
|
||||||
new_list = list[:count]
|
sort_arg_defs = self.get_sort_arg_defs()
|
||||||
elif type(sel) == type(1) and 0 <= sel < count:
|
sort_tuple = ()
|
||||||
count = sel
|
self.sort_type = ""
|
||||||
new_list = list[:count]
|
connector = ""
|
||||||
if len(list) != len(new_list):
|
for word in field:
|
||||||
msg = msg + " List reduced from " + `len(list)` \
|
sort_tuple = sort_tuple + sort_arg_defs[word][0]
|
||||||
+ " to " + `len(new_list)` + \
|
self.sort_type = self.sort_type + connector + \
|
||||||
" due to restriction <" + `sel` + ">\n"
|
sort_arg_defs[word][1]
|
||||||
|
connector = ", "
|
||||||
return new_list, msg
|
|
||||||
|
stats_list = []
|
||||||
|
for func in self.stats.keys():
|
||||||
|
cc, nc, tt, ct, callers = self.stats[func]
|
||||||
|
stats_list.append((cc, nc, tt, ct) + func_split(func) \
|
||||||
|
+ (func_std_string(func), func,) )
|
||||||
|
|
||||||
|
stats_list.sort(TupleComp(sort_tuple).compare)
|
||||||
|
|
||||||
|
self.fcn_list = fcn_list = []
|
||||||
|
for tuple in stats_list:
|
||||||
|
fcn_list.append(tuple[-1])
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
def reverse_order(self):
|
||||||
|
if self.fcn_list: self.fcn_list.reverse()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def strip_dirs(self):
|
||||||
|
oldstats = self.stats
|
||||||
|
self.stats = newstats = {}
|
||||||
|
max_name_len = 0
|
||||||
|
for func in oldstats.keys():
|
||||||
|
cc, nc, tt, ct, callers = oldstats[func]
|
||||||
|
newfunc = func_strip_path(func)
|
||||||
|
if len(func_std_string(newfunc)) > max_name_len:
|
||||||
|
max_name_len = len(func_std_string(newfunc))
|
||||||
|
newcallers = {}
|
||||||
|
for func2 in callers.keys():
|
||||||
|
newcallers[func_strip_path(func2)] = \
|
||||||
|
callers[func2]
|
||||||
|
|
||||||
|
if newstats.has_key(newfunc):
|
||||||
|
newstats[newfunc] = add_func_stats( \
|
||||||
|
newstats[newfunc],\
|
||||||
|
(cc, nc, tt, ct, newcallers))
|
||||||
|
else:
|
||||||
|
newstats[newfunc] = (cc, nc, tt, ct, newcallers)
|
||||||
|
old_top = self.top_level
|
||||||
|
self.top_level = new_top = {}
|
||||||
|
for func in old_top.keys():
|
||||||
|
new_top[func_strip_path(func)] = None
|
||||||
|
|
||||||
|
self.max_name_len = max_name_len
|
||||||
|
|
||||||
|
self.fcn_list = None
|
||||||
|
self.all_callees = None
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_print_list(self, sel_list):
|
def calc_callees(self):
|
||||||
width = self.max_name_len
|
if self.all_callees: return
|
||||||
if self.fcn_list:
|
self.all_callees = all_callees = {}
|
||||||
list = self.fcn_list[:]
|
for func in self.stats.keys():
|
||||||
msg = " Ordered by: " + self.sort_type + '\n'
|
if not all_callees.has_key(func):
|
||||||
else:
|
all_callees[func] = {}
|
||||||
list = self.stats.keys()
|
cc, nc, tt, ct, callers = self.stats[func]
|
||||||
msg = " Random listing order was used\n"
|
for func2 in callers.keys():
|
||||||
|
if not all_callees.has_key(func2):
|
||||||
|
all_callees[func2] = {}
|
||||||
|
all_callees[func2][func] = callers[func2]
|
||||||
|
return
|
||||||
|
|
||||||
for selection in sel_list:
|
#******************************************************************
|
||||||
list,msg = self.eval_print_amount(selection, list, msg)
|
# The following functions support actual printing of reports
|
||||||
|
#******************************************************************
|
||||||
|
|
||||||
count = len(list)
|
# Optional "amount" is either a line count, or a percentage of lines.
|
||||||
|
|
||||||
if not list:
|
def eval_print_amount(self, sel, list, msg):
|
||||||
return 0, list
|
new_list = list
|
||||||
print msg
|
if type(sel) == type(""):
|
||||||
if count < len(self.stats):
|
new_list = []
|
||||||
width = 0
|
for func in list:
|
||||||
for func in list:
|
if re.search(sel, func_std_string(func)):
|
||||||
if len(func_std_string(func)) > width:
|
new_list.append(func)
|
||||||
width = len(func_std_string(func))
|
else:
|
||||||
return width+2, list
|
count = len(list)
|
||||||
|
if type(sel) == type(1.0) and 0.0 <= sel < 1.0:
|
||||||
def print_stats(self, *amount):
|
count = int (count * sel + .5)
|
||||||
for filename in self.files:
|
new_list = list[:count]
|
||||||
print filename
|
elif type(sel) == type(1) and 0 <= sel < count:
|
||||||
if self.files: print
|
count = sel
|
||||||
indent = " "
|
new_list = list[:count]
|
||||||
for func in self.top_level.keys():
|
if len(list) != len(new_list):
|
||||||
print indent, func_get_function_name(func)
|
msg = msg + " List reduced from " + `len(list)` \
|
||||||
|
+ " to " + `len(new_list)` + \
|
||||||
print indent, self.total_calls, "function calls",
|
" due to restriction <" + `sel` + ">\n"
|
||||||
if self.total_calls != self.prim_calls:
|
|
||||||
print "(" + `self.prim_calls`, "primitive calls)",
|
|
||||||
print "in", fpformat.fix(self.total_tt, 3), "CPU seconds"
|
|
||||||
print
|
|
||||||
width, list = self.get_print_list(amount)
|
|
||||||
if list:
|
|
||||||
self.print_title()
|
|
||||||
for func in list:
|
|
||||||
self.print_line(func)
|
|
||||||
print
|
|
||||||
print
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
return new_list, msg
|
||||||
def print_callees(self, *amount):
|
|
||||||
width, list = self.get_print_list(amount)
|
|
||||||
if list:
|
|
||||||
self.calc_callees()
|
|
||||||
|
|
||||||
self.print_call_heading(width, "called...")
|
|
||||||
for func in list:
|
|
||||||
if self.all_callees.has_key(func):
|
|
||||||
self.print_call_line(width, \
|
|
||||||
func, self.all_callees[func])
|
|
||||||
else:
|
|
||||||
self.print_call_line(width, func, {})
|
|
||||||
print
|
|
||||||
print
|
|
||||||
return self
|
|
||||||
|
|
||||||
def print_callers(self, *amount):
|
|
||||||
width, list = self.get_print_list(amount)
|
|
||||||
if list:
|
|
||||||
self.print_call_heading(width, "was called by...")
|
|
||||||
for func in list:
|
|
||||||
cc, nc, tt, ct, callers = self.stats[func]
|
|
||||||
self.print_call_line(width, func, callers)
|
|
||||||
print
|
|
||||||
print
|
|
||||||
return self
|
|
||||||
|
|
||||||
def print_call_heading(self, name_size, column_title):
|
|
||||||
print string.ljust("Function ", name_size) + column_title
|
|
||||||
|
|
||||||
|
|
||||||
def print_call_line(self, name_size, source, call_dict):
|
|
||||||
print string.ljust(func_std_string(source), name_size),
|
|
||||||
if not call_dict:
|
|
||||||
print "--"
|
|
||||||
return
|
|
||||||
clist = call_dict.keys()
|
|
||||||
clist.sort()
|
|
||||||
name_size = name_size + 1
|
|
||||||
indent = ""
|
|
||||||
for func in clist:
|
|
||||||
name = func_std_string(func)
|
|
||||||
print indent*name_size + name + '(' \
|
|
||||||
+ `call_dict[func]`+')', \
|
|
||||||
f8(self.stats[func][3])
|
|
||||||
indent = " "
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def print_title(self):
|
def get_print_list(self, sel_list):
|
||||||
print string.rjust('ncalls', 9),
|
width = self.max_name_len
|
||||||
print string.rjust('tottime', 8),
|
if self.fcn_list:
|
||||||
print string.rjust('percall', 8),
|
list = self.fcn_list[:]
|
||||||
print string.rjust('cumtime', 8),
|
msg = " Ordered by: " + self.sort_type + '\n'
|
||||||
print string.rjust('percall', 8),
|
else:
|
||||||
print 'filename:lineno(function)'
|
list = self.stats.keys()
|
||||||
|
msg = " Random listing order was used\n"
|
||||||
|
|
||||||
|
for selection in sel_list:
|
||||||
|
list,msg = self.eval_print_amount(selection, list, msg)
|
||||||
|
|
||||||
|
count = len(list)
|
||||||
|
|
||||||
|
if not list:
|
||||||
|
return 0, list
|
||||||
|
print msg
|
||||||
|
if count < len(self.stats):
|
||||||
|
width = 0
|
||||||
|
for func in list:
|
||||||
|
if len(func_std_string(func)) > width:
|
||||||
|
width = len(func_std_string(func))
|
||||||
|
return width+2, list
|
||||||
|
|
||||||
|
def print_stats(self, *amount):
|
||||||
|
for filename in self.files:
|
||||||
|
print filename
|
||||||
|
if self.files: print
|
||||||
|
indent = " "
|
||||||
|
for func in self.top_level.keys():
|
||||||
|
print indent, func_get_function_name(func)
|
||||||
|
|
||||||
|
print indent, self.total_calls, "function calls",
|
||||||
|
if self.total_calls != self.prim_calls:
|
||||||
|
print "(" + `self.prim_calls`, "primitive calls)",
|
||||||
|
print "in", fpformat.fix(self.total_tt, 3), "CPU seconds"
|
||||||
|
print
|
||||||
|
width, list = self.get_print_list(amount)
|
||||||
|
if list:
|
||||||
|
self.print_title()
|
||||||
|
for func in list:
|
||||||
|
self.print_line(func)
|
||||||
|
print
|
||||||
|
print
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
def print_line(self, func): # hack : should print percentages
|
def print_callees(self, *amount):
|
||||||
cc, nc, tt, ct, callers = self.stats[func]
|
width, list = self.get_print_list(amount)
|
||||||
c = `nc`
|
if list:
|
||||||
if nc != cc:
|
self.calc_callees()
|
||||||
c = c + '/' + `cc`
|
|
||||||
print string.rjust(c, 9),
|
self.print_call_heading(width, "called...")
|
||||||
print f8(tt),
|
for func in list:
|
||||||
if nc == 0:
|
if self.all_callees.has_key(func):
|
||||||
print ' '*8,
|
self.print_call_line(width, \
|
||||||
else:
|
func, self.all_callees[func])
|
||||||
print f8(tt/nc),
|
else:
|
||||||
print f8(ct),
|
self.print_call_line(width, func, {})
|
||||||
if cc == 0:
|
print
|
||||||
print ' '*8,
|
print
|
||||||
else:
|
return self
|
||||||
print f8(ct/cc),
|
|
||||||
print func_std_string(func)
|
def print_callers(self, *amount):
|
||||||
|
width, list = self.get_print_list(amount)
|
||||||
|
if list:
|
||||||
|
self.print_call_heading(width, "was called by...")
|
||||||
|
for func in list:
|
||||||
|
cc, nc, tt, ct, callers = self.stats[func]
|
||||||
|
self.print_call_line(width, func, callers)
|
||||||
|
print
|
||||||
|
print
|
||||||
|
return self
|
||||||
|
|
||||||
|
def print_call_heading(self, name_size, column_title):
|
||||||
|
print string.ljust("Function ", name_size) + column_title
|
||||||
|
|
||||||
|
|
||||||
def ignore(self):
|
def print_call_line(self, name_size, source, call_dict):
|
||||||
pass # has no return value, so use at end of line :-)
|
print string.ljust(func_std_string(source), name_size),
|
||||||
|
if not call_dict:
|
||||||
|
print "--"
|
||||||
|
return
|
||||||
|
clist = call_dict.keys()
|
||||||
|
clist.sort()
|
||||||
|
name_size = name_size + 1
|
||||||
|
indent = ""
|
||||||
|
for func in clist:
|
||||||
|
name = func_std_string(func)
|
||||||
|
print indent*name_size + name + '(' \
|
||||||
|
+ `call_dict[func]`+')', \
|
||||||
|
f8(self.stats[func][3])
|
||||||
|
indent = " "
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def print_title(self):
|
||||||
|
print string.rjust('ncalls', 9),
|
||||||
|
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(self, func): # hack : should print percentages
|
||||||
|
cc, nc, tt, ct, callers = self.stats[func]
|
||||||
|
c = `nc`
|
||||||
|
if nc != cc:
|
||||||
|
c = c + '/' + `cc`
|
||||||
|
print string.rjust(c, 9),
|
||||||
|
print f8(tt),
|
||||||
|
if nc == 0:
|
||||||
|
print ' '*8,
|
||||||
|
else:
|
||||||
|
print f8(tt/nc),
|
||||||
|
print f8(ct),
|
||||||
|
if cc == 0:
|
||||||
|
print ' '*8,
|
||||||
|
else:
|
||||||
|
print f8(ct/cc),
|
||||||
|
print func_std_string(func)
|
||||||
|
|
||||||
|
|
||||||
|
def ignore(self):
|
||||||
|
pass # has no return value, so use at end of line :-)
|
||||||
|
|
||||||
|
|
||||||
class TupleComp:
|
class TupleComp:
|
||||||
"""This class provides a generic function for comparing any two tuples.
|
"""This class provides a generic function for comparing any two tuples.
|
||||||
Each instance records a list of tuple-indices (from most significant
|
Each instance records a list of tuple-indices (from most significant
|
||||||
to least significant), and sort direction (ascending or decending) for
|
to least significant), and sort direction (ascending or decending) for
|
||||||
each tuple-index. The compare functions can then be used as the function
|
each tuple-index. The compare functions can then be used as the function
|
||||||
argument to the system sort() function when a list of tuples need to be
|
argument to the system sort() function when a list of tuples need to be
|
||||||
sorted in the instances order."""
|
sorted in the instances order."""
|
||||||
|
|
||||||
def __init__(self, comp_select_list):
|
def __init__(self, comp_select_list):
|
||||||
self.comp_select_list = comp_select_list
|
self.comp_select_list = comp_select_list
|
||||||
|
|
||||||
|
def compare (self, left, right):
|
||||||
|
for index, direction in self.comp_select_list:
|
||||||
|
l = left[index]
|
||||||
|
r = right[index]
|
||||||
|
if l < r:
|
||||||
|
return -direction
|
||||||
|
if l > r:
|
||||||
|
return direction
|
||||||
|
return 0
|
||||||
|
|
||||||
def compare (self, left, right):
|
|
||||||
for index, direction in self.comp_select_list:
|
|
||||||
l = left[index]
|
|
||||||
r = right[index]
|
|
||||||
if l < r:
|
|
||||||
return -direction
|
|
||||||
if l > r:
|
|
||||||
return direction
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#**************************************************************************
|
#**************************************************************************
|
||||||
|
|
||||||
def func_strip_path(func_name):
|
def func_strip_path(func_name):
|
||||||
file, line, name = func_name
|
file, line, name = func_name
|
||||||
return os.path.basename(file), line, name
|
return os.path.basename(file), line, name
|
||||||
|
|
||||||
def func_get_function_name(func):
|
def func_get_function_name(func):
|
||||||
return func[2]
|
return func[2]
|
||||||
|
|
||||||
def func_std_string(func_name): # match what old profile produced
|
def func_std_string(func_name): # match what old profile produced
|
||||||
file, line, name = func_name
|
file, line, name = func_name
|
||||||
return file + ":" + `line` + "(" + name + ")"
|
return file + ":" + `line` + "(" + name + ")"
|
||||||
|
|
||||||
def func_split(func_name):
|
def func_split(func_name):
|
||||||
return func_name
|
return func_name
|
||||||
|
|
||||||
#**************************************************************************
|
#**************************************************************************
|
||||||
# The following functions combine statists for pairs functions.
|
# The following functions combine statists for pairs functions.
|
||||||
# The bulk of the processing involves correctly handling "call" lists,
|
# The bulk of the processing involves correctly handling "call" lists,
|
||||||
# such as callers and callees.
|
# such as callers and callees.
|
||||||
#**************************************************************************
|
#**************************************************************************
|
||||||
|
|
||||||
def add_func_stats(target, source):
|
def add_func_stats(target, source):
|
||||||
"""Add together all the stats for two profile entries."""
|
"""Add together all the stats for two profile entries."""
|
||||||
cc, nc, tt, ct, callers = source
|
cc, nc, tt, ct, callers = source
|
||||||
t_cc, t_nc, t_tt, t_ct, t_callers = target
|
t_cc, t_nc, t_tt, t_ct, t_callers = target
|
||||||
return (cc+t_cc, nc+t_nc, tt+t_tt, ct+t_ct, \
|
return (cc+t_cc, nc+t_nc, tt+t_tt, ct+t_ct, \
|
||||||
add_callers(t_callers, callers))
|
add_callers(t_callers, callers))
|
||||||
|
|
||||||
|
|
||||||
def add_callers(target, source):
|
def add_callers(target, source):
|
||||||
"""Combine two caller lists in a single list."""
|
"""Combine two caller lists in a single list."""
|
||||||
new_callers = {}
|
new_callers = {}
|
||||||
for func in target.keys():
|
for func in target.keys():
|
||||||
new_callers[func] = target[func]
|
new_callers[func] = target[func]
|
||||||
for func in source.keys():
|
for func in source.keys():
|
||||||
if new_callers.has_key(func):
|
if new_callers.has_key(func):
|
||||||
new_callers[func] = source[func] + new_callers[func]
|
new_callers[func] = source[func] + new_callers[func]
|
||||||
else:
|
else:
|
||||||
new_callers[func] = source[func]
|
new_callers[func] = source[func]
|
||||||
return new_callers
|
return new_callers
|
||||||
|
|
||||||
def count_calls(callers):
|
def count_calls(callers):
|
||||||
"""Sum the caller statistics to get total number of calls received."""
|
"""Sum the caller statistics to get total number of calls received."""
|
||||||
nc = 0
|
nc = 0
|
||||||
for func in callers.keys():
|
for func in callers.keys():
|
||||||
nc = nc + callers[func]
|
nc = nc + callers[func]
|
||||||
return nc
|
return nc
|
||||||
|
|
||||||
#**************************************************************************
|
#**************************************************************************
|
||||||
# The following functions support printing of reports
|
# The following functions support printing of reports
|
||||||
#**************************************************************************
|
#**************************************************************************
|
||||||
|
|
||||||
def f8(x):
|
def f8(x):
|
||||||
return string.rjust(fpformat.fix(x, 3), 8)
|
return string.rjust(fpformat.fix(x, 3), 8)
|
||||||
|
|
||||||
|
|
218
Lib/pty.py
218
Lib/pty.py
|
@ -1,9 +1,9 @@
|
||||||
"""Pseudo terminal utilities."""
|
"""Pseudo terminal utilities."""
|
||||||
|
|
||||||
# Bugs: No signal handling. Doesn't set slave termios and window size.
|
# Bugs: No signal handling. Doesn't set slave termios and window size.
|
||||||
# Only tested on Linux.
|
# Only tested on Linux.
|
||||||
# See: W. Richard Stevens. 1992. Advanced Programming in the
|
# See: W. Richard Stevens. 1992. Advanced Programming in the
|
||||||
# UNIX Environment. Chapter 19.
|
# UNIX Environment. Chapter 19.
|
||||||
# Author: Steen Lumholt -- with additions by Guido.
|
# Author: Steen Lumholt -- with additions by Guido.
|
||||||
|
|
||||||
from select import select
|
from select import select
|
||||||
|
@ -17,133 +17,133 @@ STDERR_FILENO = 2
|
||||||
CHILD = 0
|
CHILD = 0
|
||||||
|
|
||||||
def openpty():
|
def openpty():
|
||||||
"""openpty() -> (master_fd, slave_fd)
|
"""openpty() -> (master_fd, slave_fd)
|
||||||
Open a pty master/slave pair, using os.openpty() if possible."""
|
Open a pty master/slave pair, using os.openpty() if possible."""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return os.openpty()
|
return os.openpty()
|
||||||
except (AttributeError, OSError):
|
except (AttributeError, OSError):
|
||||||
pass
|
pass
|
||||||
master_fd, slave_name = _open_terminal()
|
master_fd, slave_name = _open_terminal()
|
||||||
slave_fd = slave_open(slave_name)
|
slave_fd = slave_open(slave_name)
|
||||||
return master_fd, slave_fd
|
return master_fd, slave_fd
|
||||||
|
|
||||||
def master_open():
|
def master_open():
|
||||||
"""master_open() -> (master_fd, slave_name)
|
"""master_open() -> (master_fd, slave_name)
|
||||||
Open a pty master and return the fd, and the filename of the slave end.
|
Open a pty master and return the fd, and the filename of the slave end.
|
||||||
Deprecated, use openpty() instead."""
|
Deprecated, use openpty() instead."""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
master_fd, slave_fd = os.openpty()
|
master_fd, slave_fd = os.openpty()
|
||||||
except (AttributeError, OSError):
|
except (AttributeError, OSError):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
slave_name = os.ttyname(slave_fd)
|
slave_name = os.ttyname(slave_fd)
|
||||||
os.close(slave_fd)
|
os.close(slave_fd)
|
||||||
return master_fd, slave_name
|
return master_fd, slave_name
|
||||||
|
|
||||||
return _open_terminal()
|
return _open_terminal()
|
||||||
|
|
||||||
def _open_terminal():
|
def _open_terminal():
|
||||||
"""Open pty master and return (master_fd, tty_name).
|
"""Open pty master and return (master_fd, tty_name).
|
||||||
SGI and generic BSD version, for when openpty() fails."""
|
SGI and generic BSD version, for when openpty() fails."""
|
||||||
try:
|
try:
|
||||||
import sgi
|
import sgi
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
tty_name, master_fd = sgi._getpty(FCNTL.O_RDWR, 0666, 0)
|
tty_name, master_fd = sgi._getpty(FCNTL.O_RDWR, 0666, 0)
|
||||||
except IOError, msg:
|
except IOError, msg:
|
||||||
raise os.error, msg
|
raise os.error, msg
|
||||||
return master_fd, tty_name
|
return master_fd, tty_name
|
||||||
for x in 'pqrstuvwxyzPQRST':
|
for x in 'pqrstuvwxyzPQRST':
|
||||||
for y in '0123456789abcdef':
|
for y in '0123456789abcdef':
|
||||||
pty_name = '/dev/pty' + x + y
|
pty_name = '/dev/pty' + x + y
|
||||||
try:
|
try:
|
||||||
fd = os.open(pty_name, FCNTL.O_RDWR)
|
fd = os.open(pty_name, FCNTL.O_RDWR)
|
||||||
except os.error:
|
except os.error:
|
||||||
continue
|
continue
|
||||||
return (fd, '/dev/tty' + x + y)
|
return (fd, '/dev/tty' + x + y)
|
||||||
raise os.error, 'out of pty devices'
|
raise os.error, 'out of pty devices'
|
||||||
|
|
||||||
def slave_open(tty_name):
|
def slave_open(tty_name):
|
||||||
"""slave_open(tty_name) -> slave_fd
|
"""slave_open(tty_name) -> slave_fd
|
||||||
Open the pty slave and acquire the controlling terminal, returning
|
Open the pty slave and acquire the controlling terminal, returning
|
||||||
opened filedescriptor.
|
opened filedescriptor.
|
||||||
Deprecated, use openpty() instead."""
|
Deprecated, use openpty() instead."""
|
||||||
|
|
||||||
return os.open(tty_name, FCNTL.O_RDWR)
|
return os.open(tty_name, FCNTL.O_RDWR)
|
||||||
|
|
||||||
def fork():
|
def fork():
|
||||||
"""fork() -> (pid, master_fd)
|
"""fork() -> (pid, master_fd)
|
||||||
Fork and make the child a session leader with a controlling terminal."""
|
Fork and make the child a session leader with a controlling terminal."""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pid, fd = os.forkpty()
|
pid, fd = os.forkpty()
|
||||||
except (AttributeError, OSError):
|
except (AttributeError, OSError):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if pid == CHILD:
|
if pid == CHILD:
|
||||||
try:
|
try:
|
||||||
os.setsid()
|
os.setsid()
|
||||||
except OSError:
|
except OSError:
|
||||||
# os.forkpty() already set us session leader
|
# os.forkpty() already set us session leader
|
||||||
pass
|
pass
|
||||||
return pid, fd
|
return pid, fd
|
||||||
|
|
||||||
master_fd, slave_fd = openpty()
|
master_fd, slave_fd = openpty()
|
||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
if pid == CHILD:
|
if pid == CHILD:
|
||||||
# Establish a new session.
|
# Establish a new session.
|
||||||
os.setsid()
|
os.setsid()
|
||||||
os.close(master_fd)
|
os.close(master_fd)
|
||||||
|
|
||||||
# Slave becomes stdin/stdout/stderr of child.
|
# Slave becomes stdin/stdout/stderr of child.
|
||||||
os.dup2(slave_fd, STDIN_FILENO)
|
os.dup2(slave_fd, STDIN_FILENO)
|
||||||
os.dup2(slave_fd, STDOUT_FILENO)
|
os.dup2(slave_fd, STDOUT_FILENO)
|
||||||
os.dup2(slave_fd, STDERR_FILENO)
|
os.dup2(slave_fd, STDERR_FILENO)
|
||||||
if (slave_fd > STDERR_FILENO):
|
if (slave_fd > STDERR_FILENO):
|
||||||
os.close (slave_fd)
|
os.close (slave_fd)
|
||||||
|
|
||||||
# Parent and child process.
|
# Parent and child process.
|
||||||
return pid, master_fd
|
return pid, master_fd
|
||||||
|
|
||||||
def _writen(fd, data):
|
def _writen(fd, data):
|
||||||
"""Write all the data to a descriptor."""
|
"""Write all the data to a descriptor."""
|
||||||
while data != '':
|
while data != '':
|
||||||
n = os.write(fd, data)
|
n = os.write(fd, data)
|
||||||
data = data[n:]
|
data = data[n:]
|
||||||
|
|
||||||
def _read(fd):
|
def _read(fd):
|
||||||
"""Default read function."""
|
"""Default read function."""
|
||||||
return os.read(fd, 1024)
|
return os.read(fd, 1024)
|
||||||
|
|
||||||
def _copy(master_fd, master_read=_read, stdin_read=_read):
|
def _copy(master_fd, master_read=_read, stdin_read=_read):
|
||||||
"""Parent copy loop.
|
"""Parent copy loop.
|
||||||
Copies
|
Copies
|
||||||
pty master -> standard output (master_read)
|
pty master -> standard output (master_read)
|
||||||
standard input -> pty master (stdin_read)"""
|
standard input -> pty master (stdin_read)"""
|
||||||
while 1:
|
while 1:
|
||||||
rfds, wfds, xfds = select(
|
rfds, wfds, xfds = select(
|
||||||
[master_fd, STDIN_FILENO], [], [])
|
[master_fd, STDIN_FILENO], [], [])
|
||||||
if master_fd in rfds:
|
if master_fd in rfds:
|
||||||
data = master_read(master_fd)
|
data = master_read(master_fd)
|
||||||
os.write(STDOUT_FILENO, data)
|
os.write(STDOUT_FILENO, data)
|
||||||
if STDIN_FILENO in rfds:
|
if STDIN_FILENO in rfds:
|
||||||
data = stdin_read(STDIN_FILENO)
|
data = stdin_read(STDIN_FILENO)
|
||||||
_writen(master_fd, data)
|
_writen(master_fd, data)
|
||||||
|
|
||||||
def spawn(argv, master_read=_read, stdin_read=_read):
|
def spawn(argv, master_read=_read, stdin_read=_read):
|
||||||
"""Create a spawned process."""
|
"""Create a spawned process."""
|
||||||
if type(argv) == type(''):
|
if type(argv) == type(''):
|
||||||
argv = (argv,)
|
argv = (argv,)
|
||||||
pid, master_fd = fork()
|
pid, master_fd = fork()
|
||||||
if pid == CHILD:
|
if pid == CHILD:
|
||||||
apply(os.execlp, (argv[0],) + argv)
|
apply(os.execlp, (argv[0],) + argv)
|
||||||
mode = tty.tcgetattr(STDIN_FILENO)
|
mode = tty.tcgetattr(STDIN_FILENO)
|
||||||
tty.setraw(STDIN_FILENO)
|
tty.setraw(STDIN_FILENO)
|
||||||
try:
|
try:
|
||||||
_copy(master_fd, master_read, stdin_read)
|
_copy(master_fd, master_read, stdin_read)
|
||||||
except:
|
except:
|
||||||
tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)
|
tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)
|
||||||
|
|
460
Lib/pyclbr.py
460
Lib/pyclbr.py
|
@ -4,7 +4,7 @@ Parse enough of a Python file to recognize class and method
|
||||||
definitions and to find out the superclasses of a class.
|
definitions and to find out the superclasses of a class.
|
||||||
|
|
||||||
The interface consists of a single function:
|
The interface consists of a single function:
|
||||||
readmodule(module, path)
|
readmodule(module, path)
|
||||||
module is the name of a Python module, path is an optional list of
|
module is the name of a Python module, path is an optional list of
|
||||||
directories where the module is to be searched. If present, path is
|
directories where the module is to be searched. If present, path is
|
||||||
prepended to the system search path sys.path.
|
prepended to the system search path sys.path.
|
||||||
|
@ -15,11 +15,11 @@ are class instances of the class Class defined here.
|
||||||
|
|
||||||
A class is described by the class Class in this module. Instances
|
A class is described by the class Class in this module. Instances
|
||||||
of this class have the following instance variables:
|
of this class have the following instance variables:
|
||||||
name -- the name of the class
|
name -- the name of the class
|
||||||
super -- a list of super classes (Class instances)
|
super -- a list of super classes (Class instances)
|
||||||
methods -- a dictionary of methods
|
methods -- a dictionary of methods
|
||||||
file -- the file in which the class was defined
|
file -- the file in which the class was defined
|
||||||
lineno -- the line in the file on which the class statement occurred
|
lineno -- the line in the file on which the class statement occurred
|
||||||
The dictionary of methods uses the method names as keys and the line
|
The dictionary of methods uses the method names as keys and the line
|
||||||
numbers on which the method was defined as values.
|
numbers on which the method was defined as values.
|
||||||
If the name of a super class is not recognized, the corresponding
|
If the name of a super class is not recognized, the corresponding
|
||||||
|
@ -64,52 +64,52 @@ TABWIDTH = 8
|
||||||
_getnext = re.compile(r"""
|
_getnext = re.compile(r"""
|
||||||
(?P<String>
|
(?P<String>
|
||||||
\""" [^"\\]* (?:
|
\""" [^"\\]* (?:
|
||||||
(?: \\. | "(?!"") )
|
(?: \\. | "(?!"") )
|
||||||
[^"\\]*
|
[^"\\]*
|
||||||
)*
|
)*
|
||||||
\"""
|
\"""
|
||||||
|
|
||||||
| ''' [^'\\]* (?:
|
| ''' [^'\\]* (?:
|
||||||
(?: \\. | '(?!'') )
|
(?: \\. | '(?!'') )
|
||||||
[^'\\]*
|
[^'\\]*
|
||||||
)*
|
)*
|
||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
|
|
||||||
| (?P<Method>
|
| (?P<Method>
|
||||||
^
|
^
|
||||||
(?P<MethodIndent> [ \t]* )
|
(?P<MethodIndent> [ \t]* )
|
||||||
def [ \t]+
|
def [ \t]+
|
||||||
(?P<MethodName> [a-zA-Z_] \w* )
|
(?P<MethodName> [a-zA-Z_] \w* )
|
||||||
[ \t]* \(
|
[ \t]* \(
|
||||||
)
|
)
|
||||||
|
|
||||||
| (?P<Class>
|
| (?P<Class>
|
||||||
^
|
^
|
||||||
(?P<ClassIndent> [ \t]* )
|
(?P<ClassIndent> [ \t]* )
|
||||||
class [ \t]+
|
class [ \t]+
|
||||||
(?P<ClassName> [a-zA-Z_] \w* )
|
(?P<ClassName> [a-zA-Z_] \w* )
|
||||||
[ \t]*
|
[ \t]*
|
||||||
(?P<ClassSupers> \( [^)\n]* \) )?
|
(?P<ClassSupers> \( [^)\n]* \) )?
|
||||||
[ \t]* :
|
[ \t]* :
|
||||||
)
|
)
|
||||||
|
|
||||||
| (?P<Import>
|
| (?P<Import>
|
||||||
^ import [ \t]+
|
^ import [ \t]+
|
||||||
(?P<ImportList> [^#;\n]+ )
|
(?P<ImportList> [^#;\n]+ )
|
||||||
)
|
)
|
||||||
|
|
||||||
| (?P<ImportFrom>
|
| (?P<ImportFrom>
|
||||||
^ from [ \t]+
|
^ from [ \t]+
|
||||||
(?P<ImportFromPath>
|
(?P<ImportFromPath>
|
||||||
[a-zA-Z_] \w*
|
[a-zA-Z_] \w*
|
||||||
(?:
|
(?:
|
||||||
[ \t]* \. [ \t]* [a-zA-Z_] \w*
|
[ \t]* \. [ \t]* [a-zA-Z_] \w*
|
||||||
)*
|
)*
|
||||||
)
|
)
|
||||||
[ \t]+
|
[ \t]+
|
||||||
import [ \t]+
|
import [ \t]+
|
||||||
(?P<ImportFromList> [^#;\n]+ )
|
(?P<ImportFromList> [^#;\n]+ )
|
||||||
)
|
)
|
||||||
""", re.VERBOSE | re.DOTALL | re.MULTILINE).search
|
""", re.VERBOSE | re.DOTALL | re.MULTILINE).search
|
||||||
|
|
||||||
|
@ -117,220 +117,220 @@ _modules = {} # cache of modules we've seen
|
||||||
|
|
||||||
# each Python class is represented by an instance of this class
|
# each Python class is represented by an instance of this class
|
||||||
class Class:
|
class Class:
|
||||||
'''Class to represent a Python class.'''
|
'''Class to represent a Python class.'''
|
||||||
def __init__(self, module, name, super, file, lineno):
|
def __init__(self, module, name, super, file, lineno):
|
||||||
self.module = module
|
self.module = module
|
||||||
self.name = name
|
self.name = name
|
||||||
if super is None:
|
if super is None:
|
||||||
super = []
|
super = []
|
||||||
self.super = super
|
self.super = super
|
||||||
self.methods = {}
|
self.methods = {}
|
||||||
self.file = file
|
self.file = file
|
||||||
self.lineno = lineno
|
self.lineno = lineno
|
||||||
|
|
||||||
def _addmethod(self, name, lineno):
|
def _addmethod(self, name, lineno):
|
||||||
self.methods[name] = lineno
|
self.methods[name] = lineno
|
||||||
|
|
||||||
class Function(Class):
|
class Function(Class):
|
||||||
'''Class to represent a top-level Python function'''
|
'''Class to represent a top-level Python function'''
|
||||||
def __init__(self, module, name, file, lineno):
|
def __init__(self, module, name, file, lineno):
|
||||||
Class.__init__(self, module, name, None, file, lineno)
|
Class.__init__(self, module, name, None, file, lineno)
|
||||||
def _addmethod(self, name, lineno):
|
def _addmethod(self, name, lineno):
|
||||||
assert 0, "Function._addmethod() shouldn't be called"
|
assert 0, "Function._addmethod() shouldn't be called"
|
||||||
|
|
||||||
def readmodule(module, path=[], inpackage=0):
|
def readmodule(module, path=[], inpackage=0):
|
||||||
'''Backwards compatible interface.
|
'''Backwards compatible interface.
|
||||||
|
|
||||||
Like readmodule_ex() but strips Function objects from the
|
Like readmodule_ex() but strips Function objects from the
|
||||||
resulting dictionary.'''
|
resulting dictionary.'''
|
||||||
|
|
||||||
dict = readmodule_ex(module, path, inpackage)
|
dict = readmodule_ex(module, path, inpackage)
|
||||||
res = {}
|
res = {}
|
||||||
for key, value in dict.items():
|
for key, value in dict.items():
|
||||||
if not isinstance(value, Function):
|
if not isinstance(value, Function):
|
||||||
res[key] = value
|
res[key] = value
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def readmodule_ex(module, path=[], inpackage=0):
|
def readmodule_ex(module, path=[], inpackage=0):
|
||||||
'''Read a module file and return a dictionary of classes.
|
'''Read a module file and return a dictionary of classes.
|
||||||
|
|
||||||
Search for MODULE in PATH and sys.path, read and parse the
|
Search for MODULE in PATH and sys.path, read and parse the
|
||||||
module and return a dictionary with one entry for each class
|
module and return a dictionary with one entry for each class
|
||||||
found in the module.'''
|
found in the module.'''
|
||||||
|
|
||||||
dict = {}
|
dict = {}
|
||||||
|
|
||||||
i = string.rfind(module, '.')
|
i = string.rfind(module, '.')
|
||||||
if i >= 0:
|
if i >= 0:
|
||||||
# Dotted module name
|
# Dotted module name
|
||||||
package = string.strip(module[:i])
|
package = string.strip(module[:i])
|
||||||
submodule = string.strip(module[i+1:])
|
submodule = string.strip(module[i+1:])
|
||||||
parent = readmodule(package, path, inpackage)
|
parent = readmodule(package, path, inpackage)
|
||||||
child = readmodule(submodule, parent['__path__'], 1)
|
child = readmodule(submodule, parent['__path__'], 1)
|
||||||
return child
|
return child
|
||||||
|
|
||||||
if _modules.has_key(module):
|
if _modules.has_key(module):
|
||||||
# we've seen this module before...
|
# we've seen this module before...
|
||||||
return _modules[module]
|
return _modules[module]
|
||||||
if module in sys.builtin_module_names:
|
if module in sys.builtin_module_names:
|
||||||
# this is a built-in module
|
# this is a built-in module
|
||||||
_modules[module] = dict
|
_modules[module] = dict
|
||||||
return dict
|
return dict
|
||||||
|
|
||||||
# search the path for the module
|
# search the path for the module
|
||||||
f = None
|
f = None
|
||||||
if inpackage:
|
if inpackage:
|
||||||
try:
|
try:
|
||||||
f, file, (suff, mode, type) = \
|
f, file, (suff, mode, type) = \
|
||||||
imp.find_module(module, path)
|
imp.find_module(module, path)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
f = None
|
f = None
|
||||||
if f is None:
|
if f is None:
|
||||||
fullpath = list(path) + sys.path
|
fullpath = list(path) + sys.path
|
||||||
f, file, (suff, mode, type) = imp.find_module(module, fullpath)
|
f, file, (suff, mode, type) = imp.find_module(module, fullpath)
|
||||||
if type == imp.PKG_DIRECTORY:
|
if type == imp.PKG_DIRECTORY:
|
||||||
dict['__path__'] = [file]
|
dict['__path__'] = [file]
|
||||||
_modules[module] = dict
|
_modules[module] = dict
|
||||||
path = [file] + path
|
path = [file] + path
|
||||||
f, file, (suff, mode, type) = \
|
f, file, (suff, mode, type) = \
|
||||||
imp.find_module('__init__', [file])
|
imp.find_module('__init__', [file])
|
||||||
if type != imp.PY_SOURCE:
|
if type != imp.PY_SOURCE:
|
||||||
# not Python source, can't do anything with this module
|
# not Python source, can't do anything with this module
|
||||||
f.close()
|
f.close()
|
||||||
_modules[module] = dict
|
_modules[module] = dict
|
||||||
return dict
|
return dict
|
||||||
|
|
||||||
_modules[module] = dict
|
_modules[module] = dict
|
||||||
imports = []
|
imports = []
|
||||||
classstack = [] # stack of (class, indent) pairs
|
classstack = [] # stack of (class, indent) pairs
|
||||||
src = f.read()
|
src = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
# To avoid having to stop the regexp at each newline, instead
|
# To avoid having to stop the regexp at each newline, instead
|
||||||
# when we need a line number we simply string.count the number of
|
# when we need a line number we simply string.count the number of
|
||||||
# newlines in the string since the last time we did this; i.e.,
|
# newlines in the string since the last time we did this; i.e.,
|
||||||
# lineno = lineno + \
|
# lineno = lineno + \
|
||||||
# string.count(src, '\n', last_lineno_pos, here)
|
# string.count(src, '\n', last_lineno_pos, here)
|
||||||
# last_lineno_pos = here
|
# last_lineno_pos = here
|
||||||
countnl = string.count
|
countnl = string.count
|
||||||
lineno, last_lineno_pos = 1, 0
|
lineno, last_lineno_pos = 1, 0
|
||||||
i = 0
|
i = 0
|
||||||
while 1:
|
while 1:
|
||||||
m = _getnext(src, i)
|
m = _getnext(src, i)
|
||||||
if not m:
|
if not m:
|
||||||
break
|
break
|
||||||
start, i = m.span()
|
start, i = m.span()
|
||||||
|
|
||||||
if m.start("Method") >= 0:
|
if m.start("Method") >= 0:
|
||||||
# found a method definition or function
|
# found a method definition or function
|
||||||
thisindent = _indent(m.group("MethodIndent"))
|
thisindent = _indent(m.group("MethodIndent"))
|
||||||
meth_name = m.group("MethodName")
|
meth_name = m.group("MethodName")
|
||||||
lineno = lineno + \
|
lineno = lineno + \
|
||||||
countnl(src, '\n',
|
countnl(src, '\n',
|
||||||
last_lineno_pos, start)
|
last_lineno_pos, start)
|
||||||
last_lineno_pos = start
|
last_lineno_pos = start
|
||||||
# close all classes indented at least as much
|
# close all classes indented at least as much
|
||||||
while classstack and \
|
while classstack and \
|
||||||
classstack[-1][1] >= thisindent:
|
classstack[-1][1] >= thisindent:
|
||||||
del classstack[-1]
|
del classstack[-1]
|
||||||
if classstack:
|
if classstack:
|
||||||
# it's a class method
|
# it's a class method
|
||||||
cur_class = classstack[-1][0]
|
cur_class = classstack[-1][0]
|
||||||
cur_class._addmethod(meth_name, lineno)
|
cur_class._addmethod(meth_name, lineno)
|
||||||
else:
|
else:
|
||||||
# it's a function
|
# it's a function
|
||||||
f = Function(module, meth_name,
|
f = Function(module, meth_name,
|
||||||
file, lineno)
|
file, lineno)
|
||||||
dict[meth_name] = f
|
dict[meth_name] = f
|
||||||
|
|
||||||
elif m.start("String") >= 0:
|
elif m.start("String") >= 0:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
elif m.start("Class") >= 0:
|
elif m.start("Class") >= 0:
|
||||||
# we found a class definition
|
# we found a class definition
|
||||||
thisindent = _indent(m.group("ClassIndent"))
|
thisindent = _indent(m.group("ClassIndent"))
|
||||||
# close all classes indented at least as much
|
# close all classes indented at least as much
|
||||||
while classstack and \
|
while classstack and \
|
||||||
classstack[-1][1] >= thisindent:
|
classstack[-1][1] >= thisindent:
|
||||||
del classstack[-1]
|
del classstack[-1]
|
||||||
lineno = lineno + \
|
lineno = lineno + \
|
||||||
countnl(src, '\n', last_lineno_pos, start)
|
countnl(src, '\n', last_lineno_pos, start)
|
||||||
last_lineno_pos = start
|
last_lineno_pos = start
|
||||||
class_name = m.group("ClassName")
|
class_name = m.group("ClassName")
|
||||||
inherit = m.group("ClassSupers")
|
inherit = m.group("ClassSupers")
|
||||||
if inherit:
|
if inherit:
|
||||||
# the class inherits from other classes
|
# the class inherits from other classes
|
||||||
inherit = string.strip(inherit[1:-1])
|
inherit = string.strip(inherit[1:-1])
|
||||||
names = []
|
names = []
|
||||||
for n in string.splitfields(inherit, ','):
|
for n in string.splitfields(inherit, ','):
|
||||||
n = string.strip(n)
|
n = string.strip(n)
|
||||||
if dict.has_key(n):
|
if dict.has_key(n):
|
||||||
# we know this super class
|
# we know this super class
|
||||||
n = dict[n]
|
n = dict[n]
|
||||||
else:
|
else:
|
||||||
c = string.splitfields(n, '.')
|
c = string.splitfields(n, '.')
|
||||||
if len(c) > 1:
|
if len(c) > 1:
|
||||||
# super class
|
# super class
|
||||||
# is of the
|
# is of the
|
||||||
# form module.class:
|
# form module.class:
|
||||||
# look in
|
# look in
|
||||||
# module for class
|
# module for class
|
||||||
m = c[-2]
|
m = c[-2]
|
||||||
c = c[-1]
|
c = c[-1]
|
||||||
if _modules.has_key(m):
|
if _modules.has_key(m):
|
||||||
d = _modules[m]
|
d = _modules[m]
|
||||||
if d.has_key(c):
|
if d.has_key(c):
|
||||||
n = d[c]
|
n = d[c]
|
||||||
names.append(n)
|
names.append(n)
|
||||||
inherit = names
|
inherit = names
|
||||||
# remember this class
|
# remember this class
|
||||||
cur_class = Class(module, class_name, inherit,
|
cur_class = Class(module, class_name, inherit,
|
||||||
file, lineno)
|
file, lineno)
|
||||||
dict[class_name] = cur_class
|
dict[class_name] = cur_class
|
||||||
classstack.append((cur_class, thisindent))
|
classstack.append((cur_class, thisindent))
|
||||||
|
|
||||||
elif m.start("Import") >= 0:
|
elif m.start("Import") >= 0:
|
||||||
# import module
|
# import module
|
||||||
for n in string.split(m.group("ImportList"), ','):
|
for n in string.split(m.group("ImportList"), ','):
|
||||||
n = string.strip(n)
|
n = string.strip(n)
|
||||||
try:
|
try:
|
||||||
# recursively read the imported module
|
# recursively read the imported module
|
||||||
d = readmodule(n, path, inpackage)
|
d = readmodule(n, path, inpackage)
|
||||||
except:
|
except:
|
||||||
##print 'module', n, 'not found'
|
##print 'module', n, 'not found'
|
||||||
pass
|
pass
|
||||||
|
|
||||||
elif m.start("ImportFrom") >= 0:
|
elif m.start("ImportFrom") >= 0:
|
||||||
# from module import stuff
|
# from module import stuff
|
||||||
mod = m.group("ImportFromPath")
|
mod = m.group("ImportFromPath")
|
||||||
names = string.split(m.group("ImportFromList"), ',')
|
names = string.split(m.group("ImportFromList"), ',')
|
||||||
try:
|
try:
|
||||||
# recursively read the imported module
|
# recursively read the imported module
|
||||||
d = readmodule(mod, path, inpackage)
|
d = readmodule(mod, path, inpackage)
|
||||||
except:
|
except:
|
||||||
##print 'module', mod, 'not found'
|
##print 'module', mod, 'not found'
|
||||||
continue
|
continue
|
||||||
# add any classes that were defined in the
|
# add any classes that were defined in the
|
||||||
# imported module to our name space if they
|
# imported module to our name space if they
|
||||||
# were mentioned in the list
|
# were mentioned in the list
|
||||||
for n in names:
|
for n in names:
|
||||||
n = string.strip(n)
|
n = string.strip(n)
|
||||||
if d.has_key(n):
|
if d.has_key(n):
|
||||||
dict[n] = d[n]
|
dict[n] = d[n]
|
||||||
elif n == '*':
|
elif n == '*':
|
||||||
# only add a name if not
|
# only add a name if not
|
||||||
# already there (to mimic what
|
# already there (to mimic what
|
||||||
# Python does internally)
|
# Python does internally)
|
||||||
# also don't add names that
|
# also don't add names that
|
||||||
# start with _
|
# start with _
|
||||||
for n in d.keys():
|
for n in d.keys():
|
||||||
if n[0] != '_' and \
|
if n[0] != '_' and \
|
||||||
not dict.has_key(n):
|
not dict.has_key(n):
|
||||||
dict[n] = d[n]
|
dict[n] = d[n]
|
||||||
else:
|
else:
|
||||||
assert 0, "regexp _getnext found something unexpected"
|
assert 0, "regexp _getnext found something unexpected"
|
||||||
|
|
||||||
return dict
|
return dict
|
||||||
|
|
||||||
def _indent(ws, _expandtabs=string.expandtabs):
|
def _indent(ws, _expandtabs=string.expandtabs):
|
||||||
return len(_expandtabs(ws, TABWIDTH))
|
return len(_expandtabs(ws, TABWIDTH))
|
||||||
|
|
|
@ -26,7 +26,7 @@ def encode(input, output, quotetabs):
|
||||||
|
|
||||||
'input' and 'output' are files with readline() and write() methods.
|
'input' and 'output' are files with readline() and write() methods.
|
||||||
The 'quotetabs' flag indicates whether tabs should be quoted.
|
The 'quotetabs' flag indicates whether tabs should be quoted.
|
||||||
"""
|
"""
|
||||||
while 1:
|
while 1:
|
||||||
line = input.readline()
|
line = input.readline()
|
||||||
if not line:
|
if not line:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue