class HTTPServer(SocketServer.TCPServer):
def server_bind(self):
- """Override server_bind to store the server name."""
- SocketServer.TCPServer.server_bind(self)
- host, port = self.socket.getsockname()
- if not host or host == '0.0.0.0':
- host = socket.gethostname()
- hostname, hostnames, hostaddrs = socket.gethostbyaddr(host)
- if '.' not in hostname:
- for host in hostnames:
- if '.' in host:
- hostname = host
- break
- self.server_name = hostname
- self.server_port = port
+ """Override server_bind to store the server name."""
+ SocketServer.TCPServer.server_bind(self)
+ host, port = self.socket.getsockname()
+ if not host or host == '0.0.0.0':
+ host = socket.gethostname()
+ hostname, hostnames, hostaddrs = socket.gethostbyaddr(host)
+ if '.' not in hostname:
+ for host in hostnames:
+ if '.' in host:
+ hostname = host
+ break
+ self.server_name = hostname
+ self.server_port = port
class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
server_version = "BaseHTTP/" + __version__
def handle(self):
- """Handle a single HTTP request.
-
- You normally don't need to override this method; see the class
- __doc__ string for information on how to handle specific HTTP
- commands such as GET and POST.
-
- """
-
- self.raw_requestline = self.rfile.readline()
- self.request_version = version = "HTTP/0.9" # Default
- requestline = self.raw_requestline
- if requestline[-2:] == '\r\n':
- requestline = requestline[:-2]
- elif requestline[-1:] == '\n':
- requestline = requestline[:-1]
- self.requestline = requestline
- words = string.split(requestline)
- if len(words) == 3:
- [command, path, version] = words
- if version[:5] != 'HTTP/':
- self.send_error(400, "Bad request version (%s)" % `version`)
- return
- elif len(words) == 2:
- [command, path] = words
- if command != 'GET':
- self.send_error(400,
- "Bad HTTP/0.9 request type (%s)" % `command`)
- return
- else:
- self.send_error(400, "Bad request syntax (%s)" % `requestline`)
- return
- self.command, self.path, self.request_version = command, path, version
- self.headers = self.MessageClass(self.rfile, 0)
- mname = 'do_' + command
- if not hasattr(self, mname):
- self.send_error(501, "Unsupported method (%s)" % `mname`)
- return
- method = getattr(self, mname)
- method()
+ """Handle a single HTTP request.
+
+ You normally don't need to override this method; see the class
+ __doc__ string for information on how to handle specific HTTP
+ commands such as GET and POST.
+
+ """
+
+ self.raw_requestline = self.rfile.readline()
+ self.request_version = version = "HTTP/0.9" # Default
+ requestline = self.raw_requestline
+ if requestline[-2:] == '\r\n':
+ requestline = requestline[:-2]
+ elif requestline[-1:] == '\n':
+ requestline = requestline[:-1]
+ self.requestline = requestline
+ words = string.split(requestline)
+ if len(words) == 3:
+ [command, path, version] = words
+ if version[:5] != 'HTTP/':
+ self.send_error(400, "Bad request version (%s)" % `version`)
+ return
+ elif len(words) == 2:
+ [command, path] = words
+ if command != 'GET':
+ self.send_error(400,
+ "Bad HTTP/0.9 request type (%s)" % `command`)
+ return
+ else:
+ self.send_error(400, "Bad request syntax (%s)" % `requestline`)
+ return
+ self.command, self.path, self.request_version = command, path, version
+ self.headers = self.MessageClass(self.rfile, 0)
+ mname = 'do_' + command
+ if not hasattr(self, mname):
+ self.send_error(501, "Unsupported method (%s)" % `mname`)
+ return
+ method = getattr(self, mname)
+ method()
def send_error(self, code, message=None):
- """Send and log an error reply.
-
- Arguments are the error code, and a detailed message.
- The detailed message defaults to the short entry matching the
- response code.
-
- This sends an error response (so it must be called before any
- output has been generated), logs the error, and finally sends
- a piece of HTML explaining the error to the user.
-
- """
-
- try:
- short, long = self.responses[code]
- except KeyError:
- short, long = '???', '???'
- if not message:
- message = short
- explain = long
- self.log_error("code %d, message %s", code, message)
- self.send_response(code, message)
- self.end_headers()
- self.wfile.write(self.error_message_format %
- {'code': code,
- 'message': message,
- 'explain': explain})
+ """Send and log an error reply.
+
+ Arguments are the error code, and a detailed message.
+ The detailed message defaults to the short entry matching the
+ response code.
+
+ This sends an error response (so it must be called before any
+ output has been generated), logs the error, and finally sends
+ a piece of HTML explaining the error to the user.
+
+ """
+
+ try:
+ short, long = self.responses[code]
+ except KeyError:
+ short, long = '???', '???'
+ if not message:
+ message = short
+ explain = long
+ self.log_error("code %d, message %s", code, message)
+ self.send_response(code, message)
+ self.end_headers()
+ self.wfile.write(self.error_message_format %
+ {'code': code,
+ 'message': message,
+ 'explain': explain})
error_message_format = DEFAULT_ERROR_MESSAGE
def send_response(self, code, message=None):
- """Send the response header and log the response code.
-
- Also send two standard headers with the server software
- version and the current date.
-
- """
- self.log_request(code)
- if message is None:
- if self.responses.has_key(code):
- message = self.responses[code][0]
- else:
- message = ''
- if self.request_version != 'HTTP/0.9':
- self.wfile.write("%s %s %s\r\n" %
- (self.protocol_version, str(code), message))
- self.send_header('Server', self.version_string())
- self.send_header('Date', self.date_time_string())
+ """Send the response header and log the response code.
+
+ Also send two standard headers with the server software
+ version and the current date.
+
+ """
+ self.log_request(code)
+ if message is None:
+ if self.responses.has_key(code):
+ message = self.responses[code][0]
+ else:
+ message = ''
+ if self.request_version != 'HTTP/0.9':
+ self.wfile.write("%s %s %s\r\n" %
+ (self.protocol_version, str(code), message))
+ self.send_header('Server', self.version_string())
+ self.send_header('Date', self.date_time_string())
def send_header(self, keyword, value):
- """Send a MIME header."""
- if self.request_version != 'HTTP/0.9':
- self.wfile.write("%s: %s\r\n" % (keyword, value))
+ """Send a MIME header."""
+ if self.request_version != 'HTTP/0.9':
+ self.wfile.write("%s: %s\r\n" % (keyword, value))
def end_headers(self):
- """Send the blank line ending the MIME headers."""
- if self.request_version != 'HTTP/0.9':
- self.wfile.write("\r\n")
+ """Send the blank line ending the MIME headers."""
+ if self.request_version != 'HTTP/0.9':
+ self.wfile.write("\r\n")
def log_request(self, code='-', size='-'):
- """Log an accepted request.
+ """Log an accepted request.
- This is called by send_reponse().
+ This is called by send_reponse().
- """
+ """
- self.log_message('"%s" %s %s',
- self.requestline, str(code), str(size))
+ self.log_message('"%s" %s %s',
+ self.requestline, str(code), str(size))
def log_error(self, *args):
- """Log an error.
+ """Log an error.
- This is called when a request cannot be fulfilled. By
- default it passes the message on to log_message().
+ This is called when a request cannot be fulfilled. By
+ default it passes the message on to log_message().
- Arguments are the same as for log_message().
+ Arguments are the same as for log_message().
- XXX This should go to the separate error log.
+ XXX This should go to the separate error log.
- """
+ """
- apply(self.log_message, args)
+ apply(self.log_message, args)
def log_message(self, format, *args):
- """Log an arbitrary message.
+ """Log an arbitrary message.
- This is used by all other logging functions. Override
- it if you have specific logging wishes.
+ This is used by all other logging functions. Override
+ it if you have specific logging wishes.
- The first argument, FORMAT, is a format string for the
- message to be logged. If the format string contains
- any % escapes requiring parameters, they should be
- specified as subsequent arguments (it's just like
- printf!).
+ The first argument, FORMAT, is a format string for the
+ message to be logged. If the format string contains
+ any % escapes requiring parameters, they should be
+ specified as subsequent arguments (it's just like
+ printf!).
- The client host and current date/time are prefixed to
- every message.
+ The client host and current date/time are prefixed to
+ every message.
- """
+ """
- sys.stderr.write("%s - - [%s] %s\n" %
- (self.address_string(),
- self.log_date_time_string(),
- format%args))
+ sys.stderr.write("%s - - [%s] %s\n" %
+ (self.address_string(),
+ self.log_date_time_string(),
+ format%args))
def version_string(self):
- """Return the server software version string."""
- return self.server_version + ' ' + self.sys_version
+ """Return the server software version string."""
+ return self.server_version + ' ' + self.sys_version
def date_time_string(self):
- """Return the current date and time formatted for a message header."""
- now = time.time()
- year, month, day, hh, mm, ss, wd, y, z = time.gmtime(now)
- s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
- self.weekdayname[wd],
- day, self.monthname[month], year,
- hh, mm, ss)
- return s
+ """Return the current date and time formatted for a message header."""
+ now = time.time()
+ year, month, day, hh, mm, ss, wd, y, z = time.gmtime(now)
+ s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
+ self.weekdayname[wd],
+ day, self.monthname[month], year,
+ hh, mm, ss)
+ return s
def log_date_time_string(self):
- """Return the current time formatted for logging."""
- now = time.time()
- year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
- s = "%02d/%3s/%04d %02d:%02d:%02d" % (
- day, self.monthname[month], year, hh, mm, ss)
- return s
+ """Return the current time formatted for logging."""
+ now = time.time()
+ year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
+ s = "%02d/%3s/%04d %02d:%02d:%02d" % (
+ day, self.monthname[month], year, hh, mm, ss)
+ return s
weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
monthname = [None,
- 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
- 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+ 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
def address_string(self):
- """Return the client address formatted for logging.
+ """Return the client address formatted for logging.
- This version looks up the full hostname using gethostbyaddr(),
- and tries to find a name that contains at least one dot.
+ This version looks up the full hostname using gethostbyaddr(),
+ and tries to find a name that contains at least one dot.
- """
+ """
- (host, port) = self.client_address
- try:
- name, names, addresses = socket.gethostbyaddr(host)
- except socket.error, msg:
- return host
- names.insert(0, name)
- for name in names:
- if '.' in name: return name
- return names[0]
+ (host, port) = self.client_address
+ try:
+ name, names, addresses = socket.gethostbyaddr(host)
+ except socket.error, msg:
+ return host
+ names.insert(0, name)
+ for name in names:
+ if '.' in name: return name
+ return names[0]
# Essentially static class variables
# form {code: (shortmessage, longmessage)}.
# See http://www.w3.org/hypertext/WWW/Protocols/HTTP/HTRESP.html
responses = {
- 200: ('OK', 'Request fulfilled, document follows'),
- 201: ('Created', 'Document created, URL follows'),
- 202: ('Accepted',
- 'Request accepted, processing continues off-line'),
- 203: ('Partial information', 'Request fulfilled from cache'),
- 204: ('No response', 'Request fulfilled, nothing follows'),
-
- 301: ('Moved', 'Object moved permanently -- see URI list'),
- 302: ('Found', 'Object moved temporarily -- see URI list'),
- 303: ('Method', 'Object moved -- see Method and URL list'),
- 304: ('Not modified',
- 'Document has not changed singe given time'),
-
- 400: ('Bad request',
- 'Bad request syntax or unsupported method'),
- 401: ('Unauthorized',
- 'No permission -- see authorization schemes'),
- 402: ('Payment required',
- 'No payment -- see charging schemes'),
- 403: ('Forbidden',
- 'Request forbidden -- authorization will not help'),
- 404: ('Not found', 'Nothing matches the given URI'),
-
- 500: ('Internal error', 'Server got itself in trouble'),
- 501: ('Not implemented',
- 'Server does not support this operation'),
- 502: ('Service temporarily overloaded',
- 'The server cannot process the request due to a high load'),
- 503: ('Gateway timeout',
- 'The gateway server did not receive a timely response'),
-
- }
+ 200: ('OK', 'Request fulfilled, document follows'),
+ 201: ('Created', 'Document created, URL follows'),
+ 202: ('Accepted',
+ 'Request accepted, processing continues off-line'),
+ 203: ('Partial information', 'Request fulfilled from cache'),
+ 204: ('No response', 'Request fulfilled, nothing follows'),
+
+ 301: ('Moved', 'Object moved permanently -- see URI list'),
+ 302: ('Found', 'Object moved temporarily -- see URI list'),
+ 303: ('Method', 'Object moved -- see Method and URL list'),
+ 304: ('Not modified',
+ 'Document has not changed singe given time'),
+
+ 400: ('Bad request',
+ 'Bad request syntax or unsupported method'),
+ 401: ('Unauthorized',
+ 'No permission -- see authorization schemes'),
+ 402: ('Payment required',
+ 'No payment -- see charging schemes'),
+ 403: ('Forbidden',
+ 'Request forbidden -- authorization will not help'),
+ 404: ('Not found', 'Nothing matches the given URI'),
+
+ 500: ('Internal error', 'Server got itself in trouble'),
+ 501: ('Not implemented',
+ 'Server does not support this operation'),
+ 502: ('Service temporarily overloaded',
+ 'The server cannot process the request due to a high load'),
+ 503: ('Gateway timeout',
+ 'The gateway server did not receive a timely response'),
+
+ }
def test(HandlerClass = BaseHTTPRequestHandler,
- ServerClass = HTTPServer):
+ ServerClass = HTTPServer):
"""Test the HTTP request handler class.
This runs an HTTP server on port 8000 (or the first command line
"""
if sys.argv[1:]:
- port = string.atoi(sys.argv[1])
+ port = string.atoi(sys.argv[1])
else:
- port = 8000
+ port = 8000
server_address = ('', port)
httpd = ServerClass(server_address, HandlerClass)
"""
def __init__(self, get, name):
- """Constructor.
+ """Constructor.
- Arguments:
+ Arguments:
- get - a function that gets the attribute value (by name)
- name - a human-readable name for the original object
- (suggestion: use repr(object))
+ get - a function that gets the attribute value (by name)
+ name - a human-readable name for the original object
+ (suggestion: use repr(object))
- """
- self._get_ = get
- self._name_ = name
+ """
+ self._get_ = get
+ self._name_ = name
def __repr__(self):
- """Return a representation string.
+ """Return a representation string.
- This includes the name passed in to the constructor, so that
- if you print the bastion during debugging, at least you have
- some idea of what it is.
+ This includes the name passed in to the constructor, so that
+ if you print the bastion during debugging, at least you have
+ some idea of what it is.
- """
- return "<Bastion for %s>" % self._name_
+ """
+ return "<Bastion for %s>" % self._name_
def __getattr__(self, name):
- """Get an as-yet undefined attribute value.
+ """Get an as-yet undefined attribute value.
- This calls the get() function that was passed to the
- constructor. The result is stored as an instance variable so
- that the next time the same attribute is requested,
- __getattr__() won't be invoked.
+ This calls the get() function that was passed to the
+ constructor. The result is stored as an instance variable so
+ that the next time the same attribute is requested,
+ __getattr__() won't be invoked.
- If the get() function raises an exception, this is simply
- passed on -- exceptions are not cached.
+ If the get() function raises an exception, this is simply
+ passed on -- exceptions are not cached.
- """
- attribute = self._get_(name)
- self.__dict__[name] = attribute
- return attribute
+ """
+ attribute = self._get_(name)
+ self.__dict__[name] = attribute
+ return attribute
def Bastion(object, filter = lambda name: name[:1] != '_',
- name=None, bastionclass=BastionClass):
+ name=None, bastionclass=BastionClass):
"""Create a bastion for an object, using an optional filter.
See the Bastion module's documentation for background.
# the user has full access to all instance variables!
def get1(name, object=object, filter=filter):
- """Internal function for Bastion(). See source comments."""
- if filter(name):
- attribute = getattr(object, name)
- if type(attribute) == MethodType:
- return attribute
- raise AttributeError, name
+ """Internal function for Bastion(). See source comments."""
+ if filter(name):
+ attribute = getattr(object, name)
+ if type(attribute) == MethodType:
+ return attribute
+ raise AttributeError, name
def get2(name, get1=get1):
- """Internal function for Bastion(). See source comments."""
- return get1(name)
+ """Internal function for Bastion(). See source comments."""
+ return get1(name)
if name is None:
- name = `object`
+ name = `object`
return bastionclass(get2, name)
def _test():
"""Test the Bastion() function."""
class Original:
- def __init__(self):
- self.sum = 0
- def add(self, n):
- self._add(n)
- def _add(self, n):
- self.sum = self.sum + n
- def total(self):
- return self.sum
+ def __init__(self):
+ self.sum = 0
+ def add(self, n):
+ self._add(n)
+ def _add(self, n):
+ self.sum = self.sum + n
+ def total(self):
+ return self.sum
o = Original()
b = Bastion(o)
testcode = """if 1:
b.add(18)
print "b.total() =", b.total()
try:
- print "b.sum =", b.sum,
+ print "b.sum =", b.sum,
except:
- print "inaccessible"
+ print "inaccessible"
else:
- print "accessible"
+ print "accessible"
try:
- print "b._add =", b._add,
+ print "b._add =", b._add,
except:
- print "inaccessible"
+ print "inaccessible"
else:
- print "accessible"
+ print "accessible"
try:
- print "b._get_.func_defaults =", b._get_.func_defaults,
+ print "b._get_.func_defaults =", b._get_.func_defaults,
except:
- print "inaccessible"
+ print "inaccessible"
else:
- print "accessible"
+ print "accessible"
\n"""
exec testcode
print '='*20, "Using rexec:", '='*20
"""
def do_POST(self):
- """Serve a POST request.
+ """Serve a POST request.
- This is only implemented for CGI scripts.
+ This is only implemented for CGI scripts.
- """
+ """
- if self.is_cgi():
- self.run_cgi()
- else:
- self.send_error(501, "Can only POST to CGI scripts")
+ if self.is_cgi():
+ self.run_cgi()
+ else:
+ self.send_error(501, "Can only POST to CGI scripts")
def send_head(self):
- """Version of send_head that support CGI scripts"""
- if self.is_cgi():
- return self.run_cgi()
- else:
- return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
+ """Version of send_head that support CGI scripts"""
+ if self.is_cgi():
+ return self.run_cgi()
+ else:
+ return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
def is_cgi(self):
- """test whether PATH corresponds to a CGI script.
+ """test whether PATH corresponds to a CGI script.
- Return a tuple (dir, rest) if PATH requires running a
- CGI script, None if not. Note that rest begins with a
- slash if it is not empty.
+ Return a tuple (dir, rest) if PATH requires running a
+ CGI script, None if not. Note that rest begins with a
+ slash if it is not empty.
- The default implementation tests whether the path
- begins with one of the strings in the list
- self.cgi_directories (and the next character is a '/'
- or the end of the string).
+ The default implementation tests whether the path
+ begins with one of the strings in the list
+ self.cgi_directories (and the next character is a '/'
+ or the end of the string).
- """
+ """
- path = self.path
+ path = self.path
- for x in self.cgi_directories:
- i = len(x)
- if path[:i] == x and (not path[i:] or path[i] == '/'):
- self.cgi_info = path[:i], path[i+1:]
- return 1
- return 0
+ for x in self.cgi_directories:
+ i = len(x)
+ if path[:i] == x and (not path[i:] or path[i] == '/'):
+ self.cgi_info = path[:i], path[i+1:]
+ return 1
+ return 0
cgi_directories = ['/cgi-bin', '/htbin']
def run_cgi(self):
- """Execute a CGI script."""
- dir, rest = self.cgi_info
- i = string.rfind(rest, '?')
- if i >= 0:
- rest, query = rest[:i], rest[i+1:]
- else:
- query = ''
- i = string.find(rest, '/')
- if i >= 0:
- script, rest = rest[:i], rest[i:]
- else:
- script, rest = rest, ''
- scriptname = dir + '/' + script
- scriptfile = self.translate_path(scriptname)
- if not os.path.exists(scriptfile):
- self.send_error(404, "No such CGI script (%s)" % `scriptname`)
- return
- if not os.path.isfile(scriptfile):
- self.send_error(403, "CGI script is not a plain file (%s)" %
- `scriptname`)
- return
- if not executable(scriptfile):
- self.send_error(403, "CGI script is not executable (%s)" %
- `scriptname`)
- return
- nobody = nobody_uid()
- self.send_response(200, "Script output follows")
- self.wfile.flush() # Always flush before forking
- pid = os.fork()
- if pid != 0:
- # Parent
- pid, sts = os.waitpid(pid, 0)
- if sts:
- self.log_error("CGI script exit status x%x" % sts)
- return
- # Child
- try:
- # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
- # XXX Much of the following could be prepared ahead of time!
- env = {}
- env['SERVER_SOFTWARE'] = self.version_string()
- env['SERVER_NAME'] = self.server.server_name
- env['GATEWAY_INTERFACE'] = 'CGI/1.1'
- env['SERVER_PROTOCOL'] = self.protocol_version
- env['SERVER_PORT'] = str(self.server.server_port)
- env['REQUEST_METHOD'] = self.command
- uqrest = urllib.unquote(rest)
- env['PATH_INFO'] = uqrest
- env['PATH_TRANSLATED'] = self.translate_path(uqrest)
- env['SCRIPT_NAME'] = scriptname
- if query:
- env['QUERY_STRING'] = query
- host = self.address_string()
- if host != self.client_address[0]:
- env['REMOTE_HOST'] = host
- env['REMOTE_ADDR'] = self.client_address[0]
- # AUTH_TYPE
- # REMOTE_USER
- # REMOTE_IDENT
- env['CONTENT_TYPE'] = self.headers.type
- length = self.headers.getheader('content-length')
- if length:
- env['CONTENT_LENGTH'] = length
- accept = []
- for line in self.headers.getallmatchingheaders('accept'):
- if line[:1] in string.whitespace:
- accept.append(string.strip(line))
- else:
- accept = accept + string.split(line[7:])
- env['HTTP_ACCEPT'] = string.joinfields(accept, ',')
- ua = self.headers.getheader('user-agent')
- if ua:
- env['HTTP_USER_AGENT'] = ua
- # XXX Other HTTP_* headers
- decoded_query = string.replace(query, '+', ' ')
- try:
- os.setuid(nobody)
- except os.error:
- pass
- os.dup2(self.rfile.fileno(), 0)
- os.dup2(self.wfile.fileno(), 1)
- print scriptfile, script, decoded_query
- os.execve(scriptfile,
- [script, decoded_query],
- env)
- except:
- self.server.handle_error(self.request, self.client_address)
- os._exit(127)
+ """Execute a CGI script."""
+ dir, rest = self.cgi_info
+ i = string.rfind(rest, '?')
+ if i >= 0:
+ rest, query = rest[:i], rest[i+1:]
+ else:
+ query = ''
+ i = string.find(rest, '/')
+ if i >= 0:
+ script, rest = rest[:i], rest[i:]
+ else:
+ script, rest = rest, ''
+ scriptname = dir + '/' + script
+ scriptfile = self.translate_path(scriptname)
+ if not os.path.exists(scriptfile):
+ self.send_error(404, "No such CGI script (%s)" % `scriptname`)
+ return
+ if not os.path.isfile(scriptfile):
+ self.send_error(403, "CGI script is not a plain file (%s)" %
+ `scriptname`)
+ return
+ if not executable(scriptfile):
+ self.send_error(403, "CGI script is not executable (%s)" %
+ `scriptname`)
+ return
+ nobody = nobody_uid()
+ self.send_response(200, "Script output follows")
+ self.wfile.flush() # Always flush before forking
+ pid = os.fork()
+ if pid != 0:
+ # Parent
+ pid, sts = os.waitpid(pid, 0)
+ if sts:
+ self.log_error("CGI script exit status x%x" % sts)
+ return
+ # Child
+ try:
+ # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
+ # XXX Much of the following could be prepared ahead of time!
+ env = {}
+ env['SERVER_SOFTWARE'] = self.version_string()
+ env['SERVER_NAME'] = self.server.server_name
+ env['GATEWAY_INTERFACE'] = 'CGI/1.1'
+ env['SERVER_PROTOCOL'] = self.protocol_version
+ env['SERVER_PORT'] = str(self.server.server_port)
+ env['REQUEST_METHOD'] = self.command
+ uqrest = urllib.unquote(rest)
+ env['PATH_INFO'] = uqrest
+ env['PATH_TRANSLATED'] = self.translate_path(uqrest)
+ env['SCRIPT_NAME'] = scriptname
+ if query:
+ env['QUERY_STRING'] = query
+ host = self.address_string()
+ if host != self.client_address[0]:
+ env['REMOTE_HOST'] = host
+ env['REMOTE_ADDR'] = self.client_address[0]
+ # AUTH_TYPE
+ # REMOTE_USER
+ # REMOTE_IDENT
+ env['CONTENT_TYPE'] = self.headers.type
+ length = self.headers.getheader('content-length')
+ if length:
+ env['CONTENT_LENGTH'] = length
+ accept = []
+ for line in self.headers.getallmatchingheaders('accept'):
+ if line[:1] in string.whitespace:
+ accept.append(string.strip(line))
+ else:
+ accept = accept + string.split(line[7:])
+ env['HTTP_ACCEPT'] = string.joinfields(accept, ',')
+ ua = self.headers.getheader('user-agent')
+ if ua:
+ env['HTTP_USER_AGENT'] = ua
+ # XXX Other HTTP_* headers
+ decoded_query = string.replace(query, '+', ' ')
+ try:
+ os.setuid(nobody)
+ except os.error:
+ pass
+ os.dup2(self.rfile.fileno(), 0)
+ os.dup2(self.wfile.fileno(), 1)
+ print scriptfile, script, decoded_query
+ os.execve(scriptfile,
+ [script, decoded_query],
+ env)
+ except:
+ self.server.handle_error(self.request, self.client_address)
+ os._exit(127)
nobody = None
"""Internal routine to get nobody's uid"""
global nobody
if nobody:
- return nobody
+ return nobody
import pwd
try:
- nobody = pwd.getpwnam('nobody')[2]
+ nobody = pwd.getpwnam('nobody')[2]
except pwd.error:
- nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
+ nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
return nobody
def executable(path):
"""Test for executable file."""
try:
- st = os.stat(path)
+ st = os.stat(path)
except os.error:
- return 0
+ return 0
return st[0] & 0111 != 0
def test(HandlerClass = CGIHTTPRequestHandler,
- ServerClass = BaseHTTPServer.HTTPServer):
+ ServerClass = BaseHTTPServer.HTTPServer):
SimpleHTTPServer.test(HandlerClass, ServerClass)
sections() -- return all the configuration section names, sans DEFAULT
options(section) -- return list of configuration options for the named
- section
+ section
read(*filenames) -- read and parse the list of named configuration files
get(section, option, raw=0) -- return a string value for the named
- option. All % interpolations are
- expanded in the return values, based on
- the defaults passed into the constructor
- and the DEFAULT section.
+ option. All % interpolations are
+ expanded in the return values, based on
+ the defaults passed into the constructor
+ and the DEFAULT section.
getint(section, options) -- like get(), but convert value to an integer
getfloat(section, options) -- like get(), but convert value to a float
getboolean(section, options) -- like get(), but convert value to
- a boolean (currently defined as 0
- or 1, only)
+ a boolean (currently defined as 0
+ or 1, only)
"""
import sys
# exception classes
class Error:
def __init__(self, msg=''):
- self.__msg = msg
+ self.__msg = msg
def __repr__(self):
- return self.__msg
+ return self.__msg
class NoSectionError(Error):
def __init__(self, section):
- Error.__init__(self, 'No section: %s' % section)
- self.section = section
+ Error.__init__(self, 'No section: %s' % section)
+ self.section = section
class DuplicateSectionError(Error):
def __init__(self, section):
- Error.__init__(self, "Section %s already exists" % section)
- self.section = section
+ Error.__init__(self, "Section %s already exists" % section)
+ self.section = section
class NoOptionError(Error):
def __init__(self, option, section):
- Error.__init__(self, "No option `%s' in section: %s" %
- (option, section))
- self.option = option
- self.section = section
+ Error.__init__(self, "No option `%s' in section: %s" %
+ (option, section))
+ self.option = option
+ self.section = section
class InterpolationError(Error):
def __init__(self, reference, option, section):
- Error.__init__(self,
- "Bad value substitution: sect `%s', opt `%s', ref `%s'"
- % (section, option, reference))
- self.reference = reference
- self.option = option
- self.section = section
+ Error.__init__(self,
+ "Bad value substitution: sect `%s', opt `%s', ref `%s'"
+ % (section, option, reference))
+ self.reference = reference
+ self.option = option
+ self.section = section
\f
class ConfigParser:
def __init__(self, defaults=None):
- self.__sections = {}
- if defaults is None:
- self.__defaults = {}
- else:
- self.__defaults = defaults
+ self.__sections = {}
+ if defaults is None:
+ self.__defaults = {}
+ else:
+ self.__defaults = defaults
def defaults(self):
- return self.__defaults
+ return self.__defaults
def sections(self):
- """Return a list of section names, excluding [DEFAULT]"""
- # self.__sections will never have [DEFAULT] in it
- return self.__sections.keys()
+ """Return a list of section names, excluding [DEFAULT]"""
+ # self.__sections will never have [DEFAULT] in it
+ return self.__sections.keys()
def add_section(self, section):
- """Create a new section in the configuration.
+ """Create a new section in the configuration.
- Raise DuplicateSectionError if a section by the specified name
- already exists.
- """
- if self.__sections.has_key(section):
- raise DuplicateSectionError(section)
- self.__sections[section] = {}
+ Raise DuplicateSectionError if a section by the specified name
+ already exists.
+ """
+ if self.__sections.has_key(section):
+ raise DuplicateSectionError(section)
+ self.__sections[section] = {}
def has_section(self, section):
- """Indicate whether the named section is present in the configuration.
+ """Indicate whether the named section is present in the configuration.
- The DEFAULT section is not acknowledged.
- """
- return self.__sections.has_key(section)
+ The DEFAULT section is not acknowledged.
+ """
+ return self.__sections.has_key(section)
def options(self, section):
- try:
- opts = self.__sections[section].copy()
- except KeyError:
- raise NoSectionError(section)
- opts.update(self.__defaults)
- return opts.keys()
+ try:
+ opts = self.__sections[section].copy()
+ except KeyError:
+ raise NoSectionError(section)
+ opts.update(self.__defaults)
+ return opts.keys()
def read(self, filenames):
- """Read and parse a list of filenames."""
- if type(filenames) is type(''):
- filenames = [filenames]
- for file in filenames:
- try:
- fp = open(file, 'r')
- self.__read(fp)
- except IOError:
- pass
+ """Read and parse a list of filenames."""
+ if type(filenames) is type(''):
+ filenames = [filenames]
+ for file in filenames:
+ try:
+ fp = open(file, 'r')
+ self.__read(fp)
+ except IOError:
+ pass
def get(self, section, option, raw=0):
- """Get an option value for a given section.
-
- All % interpolations are expanded in the return values, based
- on the defaults passed into the constructor.
-
- The section DEFAULT is special.
- """
- try:
- sectdict = self.__sections[section].copy()
- except KeyError:
- if section == DEFAULTSECT:
- sectdict = {}
- else:
- raise NoSectionError(section)
- d = self.__defaults.copy()
- d.update(sectdict)
- option = string.lower(option)
- try:
- rawval = d[option]
- except KeyError:
- raise NoOptionError(option, section)
- # do the string interpolation
- if raw:
- return rawval
- try:
- return rawval % d
- except KeyError, key:
- raise InterpolationError(key, option, section)
+ """Get an option value for a given section.
+
+ All % interpolations are expanded in the return values, based
+ on the defaults passed into the constructor.
+
+ The section DEFAULT is special.
+ """
+ try:
+ sectdict = self.__sections[section].copy()
+ except KeyError:
+ if section == DEFAULTSECT:
+ sectdict = {}
+ else:
+ raise NoSectionError(section)
+ d = self.__defaults.copy()
+ d.update(sectdict)
+ option = string.lower(option)
+ try:
+ rawval = d[option]
+ except KeyError:
+ raise NoOptionError(option, section)
+ # do the string interpolation
+ if raw:
+ return rawval
+ try:
+ return rawval % d
+ except KeyError, key:
+ raise InterpolationError(key, option, section)
def __get(self, section, conv, option):
- return conv(self.get(section, option))
+ return conv(self.get(section, option))
def getint(self, section, option):
- return self.__get(section, string.atoi, option)
+ return self.__get(section, string.atoi, option)
def getfloat(self, section, option):
- return self.__get(section, string.atof, option)
+ return self.__get(section, string.atof, option)
def getboolean(self, section, option):
- v = self.get(section, option)
- val = string.atoi(v)
- if val not in (0, 1):
- raise ValueError, 'Not a boolean: %s' % v
- return val
+ v = self.get(section, option)
+ val = string.atoi(v)
+ if val not in (0, 1):
+ raise ValueError, 'Not a boolean: %s' % v
+ return val
def __read(self, fp):
- """Parse a sectioned setup file.
-
- The sections in setup file contains a title line at the top,
- indicated by a name in square brackets (`[]'), plus key/value
- options lines, indicated by `name: value' format lines.
- Continuation are represented by an embedded newline then
- leading whitespace. Blank lines, lines beginning with a '#',
- and just about everything else is ignored.
- """
- cursect = None # None, or a dictionary
- optname = None
- lineno = 0
- while 1:
- line = fp.readline()
- if not line:
- break
- lineno = lineno + 1
- # comment or blank line?
- if string.strip(line) == '' or line[0] in '#;':
- continue
- if string.lower(string.split(line)[0]) == 'rem' \
- and line[0] == "r": # no leading whitespace
- continue
- # continuation line?
- if line[0] in ' \t' and cursect <> None and optname:
- value = string.strip(line)
- if value:
- cursect = cursect[optname] + '\n ' + value
- # a section header?
- elif secthead_cre.match(line) >= 0:
- sectname = secthead_cre.group(1)
- if self.__sections.has_key(sectname):
- cursect = self.__sections[sectname]
- elif sectname == DEFAULTSECT:
- cursect = self.__defaults
- else:
- cursect = {'name': sectname}
- self.__sections[sectname] = cursect
- # So sections can't start with a continuation line.
- optname = None
- # an option line?
- elif option_cre.match(line) >= 0:
- optname, optval = option_cre.group(1, 3)
- optname = string.lower(optname)
- optval = string.strip(optval)
- # allow empty values
- if optval == '""':
- optval = ''
- cursect[optname] = optval
- # an error
- else:
- print 'Error in %s at %d: %s', (fp.name, lineno, `line`)
+ """Parse a sectioned setup file.
+
+ The sections in setup file contains a title line at the top,
+ indicated by a name in square brackets (`[]'), plus key/value
+ options lines, indicated by `name: value' format lines.
+ Continuation are represented by an embedded newline then
+ leading whitespace. Blank lines, lines beginning with a '#',
+ and just about everything else is ignored.
+ """
+ cursect = None # None, or a dictionary
+ optname = None
+ lineno = 0
+ while 1:
+ line = fp.readline()
+ if not line:
+ break
+ lineno = lineno + 1
+ # comment or blank line?
+ if string.strip(line) == '' or line[0] in '#;':
+ continue
+ if string.lower(string.split(line)[0]) == 'rem' \
+ and line[0] == "r": # no leading whitespace
+ continue
+ # continuation line?
+ if line[0] in ' \t' and cursect <> None and optname:
+ value = string.strip(line)
+ if value:
+ cursect = cursect[optname] + '\n ' + value
+ # a section header?
+ elif secthead_cre.match(line) >= 0:
+ sectname = secthead_cre.group(1)
+ if self.__sections.has_key(sectname):
+ cursect = self.__sections[sectname]
+ elif sectname == DEFAULTSECT:
+ cursect = self.__defaults
+ else:
+ cursect = {'name': sectname}
+ self.__sections[sectname] = cursect
+ # So sections can't start with a continuation line.
+ optname = None
+ # an option line?
+ elif option_cre.match(line) >= 0:
+ optname, optval = option_cre.group(1, 3)
+ optname = string.lower(optname)
+ optval = string.strip(optval)
+ # allow empty values
+ if optval == '""':
+ optval = ''
+ cursect[optname] = optval
+ # an error
+ else:
+ print 'Error in %s at %d: %s', (fp.name, lineno, `line`)
w.startmultipartbody(subtype)
for each part:
subwriter = w.nextpart()
- ...use the subwriter's methods to create the subpart...
+ ...use the subwriter's methods to create the subpart...
w.lastpart()
The subwriter is another MimeWriter instance, and should be
"""
def __init__(self, fp):
- self._fp = fp
- self._headers = []
+ self._fp = fp
+ self._headers = []
def addheader(self, key, value, prefix=0):
- lines = string.splitfields(value, "\n")
- while lines and not lines[-1]: del lines[-1]
- while lines and not lines[0]: del lines[0]
- for i in range(1, len(lines)):
- lines[i] = " " + string.strip(lines[i])
- value = string.joinfields(lines, "\n") + "\n"
- line = key + ": " + value
- if prefix:
- self._headers.insert(0, line)
- else:
- self._headers.append(line)
+ lines = string.splitfields(value, "\n")
+ while lines and not lines[-1]: del lines[-1]
+ while lines and not lines[0]: del lines[0]
+ for i in range(1, len(lines)):
+ lines[i] = " " + string.strip(lines[i])
+ value = string.joinfields(lines, "\n") + "\n"
+ line = key + ": " + value
+ if prefix:
+ self._headers.insert(0, line)
+ else:
+ self._headers.append(line)
def flushheaders(self):
- self._fp.writelines(self._headers)
- self._headers = []
+ self._fp.writelines(self._headers)
+ self._headers = []
def startbody(self, ctype, plist=[], prefix=1):
- for name, value in plist:
- ctype = ctype + ';\n %s=\"%s\"' % (name, value)
- self.addheader("Content-Type", ctype, prefix=prefix)
- self.flushheaders()
- self._fp.write("\n")
- return self._fp
+ for name, value in plist:
+ ctype = ctype + ';\n %s=\"%s\"' % (name, value)
+ self.addheader("Content-Type", ctype, prefix=prefix)
+ self.flushheaders()
+ self._fp.write("\n")
+ return self._fp
def startmultipartbody(self, subtype, boundary=None, plist=[], prefix=1):
- self._boundary = boundary or mimetools.choose_boundary()
- return self.startbody("multipart/" + subtype,
- [("boundary", self._boundary)] + plist,
- prefix=prefix)
+ self._boundary = boundary or mimetools.choose_boundary()
+ return self.startbody("multipart/" + subtype,
+ [("boundary", self._boundary)] + plist,
+ prefix=prefix)
def nextpart(self):
- self._fp.write("\n--" + self._boundary + "\n")
- return self.__class__(self._fp)
+ self._fp.write("\n--" + self._boundary + "\n")
+ return self.__class__(self._fp)
def lastpart(self):
- self._fp.write("\n--" + self._boundary + "--\n")
+ self._fp.write("\n--" + self._boundary + "--\n")
if __name__ == '__main__':
# exceptions, but also when -X option is used.
try:
class Empty(Exception):
- pass
+ pass
except TypeError:
# string based exceptions
- Empty = 'Queue.Empty' # Exception raised by get_nowait()
+ Empty = 'Queue.Empty' # Exception raised by get_nowait()
class Queue:
def __init__(self, maxsize):
- """Initialize a queue object with a given maximum size.
+ """Initialize a queue object with a given maximum size.
- If maxsize is <= 0, the queue size is infinite.
- """
- import thread
- self._init(maxsize)
- self.mutex = thread.allocate_lock()
- self.esema = thread.allocate_lock()
- self.esema.acquire_lock()
- self.fsema = thread.allocate_lock()
+ If maxsize is <= 0, the queue size is infinite.
+ """
+ import thread
+ self._init(maxsize)
+ self.mutex = thread.allocate_lock()
+ self.esema = thread.allocate_lock()
+ self.esema.acquire_lock()
+ self.fsema = thread.allocate_lock()
def qsize(self):
- """Returns the approximate size of the queue (not reliable!)."""
- self.mutex.acquire_lock()
- n = self._qsize()
- self.mutex.release_lock()
- return n
+ """Returns the approximate size of the queue (not reliable!)."""
+ self.mutex.acquire_lock()
+ n = self._qsize()
+ self.mutex.release_lock()
+ return n
def empty(self):
- """Returns 1 if the queue is empty, 0 otherwise (not reliable!)."""
- self.mutex.acquire_lock()
- n = self._empty()
- self.mutex.release_lock()
- return n
+ """Returns 1 if the queue is empty, 0 otherwise (not reliable!)."""
+ self.mutex.acquire_lock()
+ n = self._empty()
+ self.mutex.release_lock()
+ return n
def full(self):
- """Returns 1 if the queue is full, 0 otherwise (not reliable!)."""
- self.mutex.acquire_lock()
- n = self._full()
- self.mutex.release_lock()
- return n
+ """Returns 1 if the queue is full, 0 otherwise (not reliable!)."""
+ self.mutex.acquire_lock()
+ n = self._full()
+ self.mutex.release_lock()
+ return n
def put(self, item):
- """Put an item into the queue."""
- self.fsema.acquire_lock()
- self.mutex.acquire_lock()
- was_empty = self._empty()
- self._put(item)
- if was_empty:
- self.esema.release_lock()
- if not self._full():
- self.fsema.release_lock()
- self.mutex.release_lock()
+ """Put an item into the queue."""
+ self.fsema.acquire_lock()
+ self.mutex.acquire_lock()
+ was_empty = self._empty()
+ self._put(item)
+ if was_empty:
+ self.esema.release_lock()
+ if not self._full():
+ self.fsema.release_lock()
+ self.mutex.release_lock()
def get(self):
- """Gets and returns an item from the queue.
- This method blocks if necessary until an item is available.
- """
- self.esema.acquire_lock()
- self.mutex.acquire_lock()
- was_full = self._full()
- item = self._get()
- if was_full:
- self.fsema.release_lock()
- if not self._empty():
- self.esema.release_lock()
- self.mutex.release_lock()
- return item
+ """Gets and returns an item from the queue.
+ This method blocks if necessary until an item is available.
+ """
+ self.esema.acquire_lock()
+ self.mutex.acquire_lock()
+ was_full = self._full()
+ item = self._get()
+ if was_full:
+ self.fsema.release_lock()
+ if not self._empty():
+ self.esema.release_lock()
+ self.mutex.release_lock()
+ return item
# Get an item from the queue if one is immediately available,
# raise Empty if the queue is empty or temporarily unavailable
def get_nowait(self):
- """Gets and returns an item from the queue.
- Only gets an item if one is immediately available, Otherwise
- this raises the Empty exception if the queue is empty or
- temporarily unavailable.
- """
- locked = self.esema.acquire_lock(0)
- self.mutex.acquire_lock()
- if self._empty():
- # The queue is empty -- we can't have esema
- self.mutex.release_lock()
- raise Empty
- if not locked:
- locked = self.esema.acquire_lock(0)
- if not locked:
- # Somebody else has esema
- # but we have mutex --
- # go out of their way
- self.mutex.release_lock()
- raise Empty
- was_full = self._full()
- item = self._get()
- if was_full:
- self.fsema.release_lock()
- if not self._empty():
- self.esema.release_lock()
- self.mutex.release_lock()
- return item
+ """Gets and returns an item from the queue.
+ Only gets an item if one is immediately available, Otherwise
+ this raises the Empty exception if the queue is empty or
+ temporarily unavailable.
+ """
+ locked = self.esema.acquire_lock(0)
+ self.mutex.acquire_lock()
+ if self._empty():
+ # The queue is empty -- we can't have esema
+ self.mutex.release_lock()
+ raise Empty
+ if not locked:
+ locked = self.esema.acquire_lock(0)
+ if not locked:
+ # Somebody else has esema
+ # but we have mutex --
+ # go out of their way
+ self.mutex.release_lock()
+ raise Empty
+ was_full = self._full()
+ item = self._get()
+ if was_full:
+ self.fsema.release_lock()
+ if not self._empty():
+ self.esema.release_lock()
+ self.mutex.release_lock()
+ return item
# XXX Need to define put_nowait() as well.
# Initialize the queue representation
def _init(self, maxsize):
- self.maxsize = maxsize
- self.queue = []
+ self.maxsize = maxsize
+ self.queue = []
def _qsize(self):
- return len(self.queue)
+ return len(self.queue)
# Check wheter the queue is empty
def _empty(self):
- return not self.queue
+ return not self.queue
# Check whether the queue is full
def _full(self):
- return self.maxsize > 0 and len(self.queue) == self.maxsize
+ return self.maxsize > 0 and len(self.queue) == self.maxsize
# Put a new item in the queue
def _put(self, item):
- self.queue.append(item)
+ self.queue.append(item)
# Get an item from the queue
def _get(self):
- item = self.queue[0]
- del self.queue[0]
- return item
+ item = self.queue[0]
+ del self.queue[0]
+ return item
server_version = "SimpleHTTP/" + __version__
def do_GET(self):
- """Serve a GET request."""
- f = self.send_head()
- if f:
- self.copyfile(f, self.wfile)
- f.close()
+ """Serve a GET request."""
+ f = self.send_head()
+ if f:
+ self.copyfile(f, self.wfile)
+ f.close()
def do_HEAD(self):
- """Serve a HEAD request."""
- f = self.send_head()
- if f:
- f.close()
+ """Serve a HEAD request."""
+ f = self.send_head()
+ if f:
+ f.close()
def send_head(self):
- """Common code for GET and HEAD commands.
-
- This sends the response code and MIME headers.
-
- Return value is either a file object (which has to be copied
- to the outputfile by the caller unless the command was HEAD,
- and must be closed by the caller under all circumstances), or
- None, in which case the caller has nothing further to do.
-
- """
- path = self.translate_path(self.path)
- if os.path.isdir(path):
- self.send_error(403, "Directory listing not supported")
- return None
- try:
- f = open(path)
- except IOError:
- self.send_error(404, "File not found")
- return None
- self.send_response(200)
- self.send_header("Content-type", self.guess_type(path))
- self.end_headers()
- return f
+ """Common code for GET and HEAD commands.
+
+ This sends the response code and MIME headers.
+
+ Return value is either a file object (which has to be copied
+ to the outputfile by the caller unless the command was HEAD,
+ and must be closed by the caller under all circumstances), or
+ None, in which case the caller has nothing further to do.
+
+ """
+ path = self.translate_path(self.path)
+ if os.path.isdir(path):
+ self.send_error(403, "Directory listing not supported")
+ return None
+ try:
+ f = open(path)
+ except IOError:
+ self.send_error(404, "File not found")
+ return None
+ self.send_response(200)
+ self.send_header("Content-type", self.guess_type(path))
+ self.end_headers()
+ return f
def translate_path(self, path):
- """Translate a /-separated PATH to the local filename syntax.
-
- Components that mean special things to the local file system
- (e.g. drive or directory names) are ignored. (XXX They should
- probably be diagnosed.)
-
- """
- path = posixpath.normpath(path)
- words = string.splitfields(path, '/')
- words = filter(None, words)
- path = os.getcwd()
- for word in words:
- drive, word = os.path.splitdrive(word)
- head, word = os.path.split(word)
- if word in (os.curdir, os.pardir): continue
- path = os.path.join(path, word)
- return path
+ """Translate a /-separated PATH to the local filename syntax.
+
+ Components that mean special things to the local file system
+ (e.g. drive or directory names) are ignored. (XXX They should
+ probably be diagnosed.)
+
+ """
+ path = posixpath.normpath(path)
+ words = string.splitfields(path, '/')
+ words = filter(None, words)
+ path = os.getcwd()
+ for word in words:
+ drive, word = os.path.splitdrive(word)
+ head, word = os.path.split(word)
+ if word in (os.curdir, os.pardir): continue
+ path = os.path.join(path, word)
+ return path
def copyfile(self, source, outputfile):
- """Copy all data between two file objects.
+ """Copy all data between two file objects.
- The SOURCE argument is a file object open for reading
- (or anything with a read() method) and the DESTINATION
- argument is a file object open for writing (or
- anything with a write() method).
+ The SOURCE argument is a file object open for reading
+ (or anything with a read() method) and the DESTINATION
+ argument is a file object open for writing (or
+ anything with a write() method).
- The only reason for overriding this would be to change
- the block size or perhaps to replace newlines by CRLF
- -- note however that this the default server uses this
- to copy binary data as well.
+ The only reason for overriding this would be to change
+ the block size or perhaps to replace newlines by CRLF
+ -- note however that this the default server uses this
+ to copy binary data as well.
- """
+ """
- BLOCKSIZE = 8192
- while 1:
- data = source.read(BLOCKSIZE)
- if not data: break
- outputfile.write(data)
+ BLOCKSIZE = 8192
+ while 1:
+ data = source.read(BLOCKSIZE)
+ if not data: break
+ outputfile.write(data)
def guess_type(self, path):
- """Guess the type of a file.
+ """Guess the type of a file.
- Argument is a PATH (a filename).
+ Argument is a PATH (a filename).
- Return value is a string of the form type/subtype,
- usable for a MIME Content-type header.
+ Return value is a string of the form type/subtype,
+ usable for a MIME Content-type header.
- The default implementation looks the file's extension
- up in the table self.extensions_map, using text/plain
- as a default; however it would be permissible (if
- slow) to look inside the data to make a better guess.
+ The default implementation looks the file's extension
+ up in the table self.extensions_map, using text/plain
+ as a default; however it would be permissible (if
+ slow) to look inside the data to make a better guess.
- """
+ """
- base, ext = posixpath.splitext(path)
- if self.extensions_map.has_key(ext):
- return self.extensions_map[ext]
- ext = string.lower(ext)
- if self.extensions_map.has_key(ext):
- return self.extensions_map[ext]
- else:
- return self.extensions_map['']
+ base, ext = posixpath.splitext(path)
+ if self.extensions_map.has_key(ext):
+ return self.extensions_map[ext]
+ ext = string.lower(ext)
+ if self.extensions_map.has_key(ext):
+ return self.extensions_map[ext]
+ else:
+ return self.extensions_map['']
extensions_map = {
- '': 'text/plain', # Default, *must* be present
- '.html': 'text/html',
- '.htm': 'text/html',
- '.gif': 'image/gif',
- '.jpg': 'image/jpeg',
- '.jpeg': 'image/jpeg',
- }
+ '': 'text/plain', # Default, *must* be present
+ '.html': 'text/html',
+ '.htm': 'text/html',
+ '.gif': 'image/gif',
+ '.jpg': 'image/jpeg',
+ '.jpeg': 'image/jpeg',
+ }
def test(HandlerClass = SimpleHTTPRequestHandler,
- ServerClass = SocketServer.TCPServer):
+ ServerClass = SocketServer.TCPServer):
BaseHTTPServer.test(HandlerClass, ServerClass)
This module tries to capture the various aspects of defining a server:
- address family:
- - AF_INET: IP (Internet Protocol) sockets (default)
- - AF_UNIX: Unix domain sockets
- - others, e.g. AF_DECNET are conceivable (see <socket.h>
+ - AF_INET: IP (Internet Protocol) sockets (default)
+ - AF_UNIX: Unix domain sockets
+ - others, e.g. AF_DECNET are conceivable (see <socket.h>
- socket type:
- - SOCK_STREAM (reliable stream, e.g. TCP)
- - SOCK_DGRAM (datagrams, e.g. UDP)
+ - SOCK_STREAM (reliable stream, e.g. TCP)
+ - SOCK_DGRAM (datagrams, e.g. UDP)
- client address verification before further looking at the request
- (This is actually a hook for any processing that needs to look
- at the request before anything else, e.g. logging)
+ (This is actually a hook for any processing that needs to look
+ at the request before anything else, e.g. logging)
- how to handle multiple requests:
- - synchronous (one request is handled at a time)
- - forking (each request is handled by a new process)
- - threading (each request is handled by a new thread)
+ - synchronous (one request is handled at a time)
+ - forking (each request is handled by a new process)
+ - threading (each request is handled by a new thread)
The classes in this module favor the server type that is simplest to
write: a synchronous TCP/IP server. This is bad class design, but
There are four classes in an inheritance diagram that represent
synchronous servers of four types:
- +-----------+ +------------------+
- | TCPServer |------->| UnixStreamServer |
- +-----------+ +------------------+
- |
- v
- +-----------+ +--------------------+
- | UDPServer |------->| UnixDatagramServer |
- +-----------+ +--------------------+
+ +-----------+ +------------------+
+ | TCPServer |------->| UnixStreamServer |
+ +-----------+ +------------------+
+ |
+ v
+ +-----------+ +--------------------+
+ | UDPServer |------->| UnixDatagramServer |
+ +-----------+ +--------------------+
Note that UnixDatagramServer derives from UDPServer, not from
UnixStreamServer -- the only difference between an IP and a Unix
using the ForkingServer and ThreadingServer mix-in classes. For
instance, a threading UDP server class is created as follows:
- class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
+ class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
The Mix-in class must come first, since it overrides a method defined
in UDPServer!
- __init__(server_address, RequestHandlerClass)
- serve_forever()
- - handle_request() # if you don't use serve_forever()
- - fileno() -> int # for select()
+ - handle_request() # if you don't use serve_forever()
+ - fileno() -> int # for select()
Methods that may be overridden:
request_queue_size = 5
def __init__(self, server_address, RequestHandlerClass):
- """Constructor. May be extended, do not override."""
- self.server_address = server_address
- self.RequestHandlerClass = RequestHandlerClass
- self.socket = socket.socket(self.address_family,
- self.socket_type)
- self.server_bind()
- self.server_activate()
+ """Constructor. May be extended, do not override."""
+ self.server_address = server_address
+ self.RequestHandlerClass = RequestHandlerClass
+ self.socket = socket.socket(self.address_family,
+ self.socket_type)
+ self.server_bind()
+ self.server_activate()
def server_bind(self):
- """Called by constructor to bind the socket.
+ """Called by constructor to bind the socket.
- May be overridden.
+ May be overridden.
- """
- self.socket.bind(self.server_address)
+ """
+ self.socket.bind(self.server_address)
def server_activate(self):
- """Called by constructor to activate the server.
+ """Called by constructor to activate the server.
- May be overridden.
+ May be overridden.
- """
- self.socket.listen(self.request_queue_size)
+ """
+ self.socket.listen(self.request_queue_size)
def fileno(self):
- """Return socket file number.
+ """Return socket file number.
- Interface required by select().
+ Interface required by select().
- """
- return self.socket.fileno()
+ """
+ return self.socket.fileno()
def serve_forever(self):
- """Handle one request at a time until doomsday."""
- while 1:
- self.handle_request()
+ """Handle one request at a time until doomsday."""
+ while 1:
+ self.handle_request()
# The distinction between handling, getting, processing and
# finishing a request is fairly arbitrary. Remember:
# this constructor will handle the request all by itself
def handle_request(self):
- """Handle one request, possibly blocking."""
- request, client_address = self.get_request()
- if self.verify_request(request, client_address):
- try:
- self.process_request(request, client_address)
- except:
- self.handle_error(request, client_address)
+ """Handle one request, possibly blocking."""
+ request, client_address = self.get_request()
+ if self.verify_request(request, client_address):
+ try:
+ self.process_request(request, client_address)
+ except:
+ self.handle_error(request, client_address)
def get_request(self):
- """Get the request and client address from the socket.
+ """Get the request and client address from the socket.
- May be overridden.
+ May be overridden.
- """
- return self.socket.accept()
+ """
+ return self.socket.accept()
def verify_request(self, request, client_address):
- """Verify the request. May be overridden.
+ """Verify the request. May be overridden.
- Return true if we should proceed with this request.
+ Return true if we should proceed with this request.
- """
- return 1
+ """
+ return 1
def process_request(self, request, client_address):
- """Call finish_request.
+ """Call finish_request.
- Overridden by ForkingMixIn and ThreadingMixIn.
+ Overridden by ForkingMixIn and ThreadingMixIn.
- """
- self.finish_request(request, client_address)
+ """
+ self.finish_request(request, client_address)
def finish_request(self, request, client_address):
- """Finish one request by instantiating RequestHandlerClass."""
- self.RequestHandlerClass(request, client_address, self)
+ """Finish one request by instantiating RequestHandlerClass."""
+ self.RequestHandlerClass(request, client_address, self)
def handle_error(self, request, client_address):
- """Handle an error gracefully. May be overridden.
+ """Handle an error gracefully. May be overridden.
- The default is to print a traceback and continue.
+ The default is to print a traceback and continue.
- """
- print '-'*40
- print 'Exception happened during processing of request from',
- print client_address
- import traceback
- traceback.print_exc()
- print '-'*40
+ """
+ print '-'*40
+ print 'Exception happened during processing of request from',
+ print client_address
+ import traceback
+ traceback.print_exc()
+ print '-'*40
class UDPServer(TCPServer):
max_packet_size = 8192
def get_request(self):
- return self.socket.recvfrom(self.max_packet_size)
+ return self.socket.recvfrom(self.max_packet_size)
if hasattr(socket, 'AF_UNIX'):
class UnixStreamServer(TCPServer):
- address_family = socket.AF_UNIX
+ address_family = socket.AF_UNIX
class UnixDatagramServer(UDPServer):
- address_family = socket.AF_UNIX
+ address_family = socket.AF_UNIX
class ForkingMixIn:
active_children = None
def collect_children(self):
- """Internal routine to wait for died children."""
- while self.active_children:
- pid, status = os.waitpid(0, os.WNOHANG)
- if not pid: break
- self.active_children.remove(pid)
+ """Internal routine to wait for died children."""
+ while self.active_children:
+ pid, status = os.waitpid(0, os.WNOHANG)
+ if not pid: break
+ self.active_children.remove(pid)
def process_request(self, request, client_address):
- """Fork a new subprocess to process the request."""
- self.collect_children()
- pid = os.fork()
- if pid:
- # Parent process
- if self.active_children is None:
- self.active_children = []
- self.active_children.append(pid)
- return
- else:
- # Child process.
- # This must never return, hence os._exit()!
- try:
- self.finish_request(request, client_address)
- os._exit(0)
- except:
- try:
- self.handle_error(request,
- client_address)
- finally:
- os._exit(1)
+ """Fork a new subprocess to process the request."""
+ self.collect_children()
+ pid = os.fork()
+ if pid:
+ # Parent process
+ if self.active_children is None:
+ self.active_children = []
+ self.active_children.append(pid)
+ return
+ else:
+ # Child process.
+ # This must never return, hence os._exit()!
+ try:
+ self.finish_request(request, client_address)
+ os._exit(0)
+ except:
+ try:
+ self.handle_error(request,
+ client_address)
+ finally:
+ os._exit(1)
class ThreadingMixIn:
"""Mix-in class to handle each request in a new thread."""
def process_request(self, request, client_address):
- """Start a new thread to process the request."""
- import thread
- thread.start_new_thread(self.finish_request,
- (request, client_address))
+ """Start a new thread to process the request."""
+ import thread
+ thread.start_new_thread(self.finish_request,
+ (request, client_address))
class ForkingUDPServer(ForkingMixIn, UDPServer): pass
"""
def __init__(self, request, client_address, server):
- self.request = request
- self.client_address = client_address
- self.server = server
- try:
- self.setup()
- self.handle()
- self.finish()
- finally:
- sys.exc_traceback = None # Help garbage collection
+ self.request = request
+ self.client_address = client_address
+ self.server = server
+ try:
+ self.setup()
+ self.handle()
+ self.finish()
+ finally:
+ sys.exc_traceback = None # Help garbage collection
def setup(self):
- pass
+ pass
def __del__(self):
- pass
+ pass
def handle(self):
- pass
+ pass
def finish(self):
- pass
+ pass
# The following two classes make it possible to use the same service
"""Define self.rfile and self.wfile for stream sockets."""
def setup(self):
- self.connection = self.request
- self.rfile = self.connection.makefile('rb', 0)
- self.wfile = self.connection.makefile('wb', 0)
+ self.connection = self.request
+ self.rfile = self.connection.makefile('rb', 0)
+ self.wfile = self.connection.makefile('wb', 0)
def finish(self):
- self.wfile.flush()
+ self.wfile.flush()
class DatagramRequestHandler(BaseRequestHandler):
"""Define self.rfile and self.wfile for datagram sockets."""
def setup(self):
- import StringIO
- self.packet, self.socket = self.request
- self.rfile = StringIO.StringIO(self.packet)
- self.wfile = StringIO.StringIO(self.packet)
+ import StringIO
+ self.packet, self.socket = self.request
+ self.rfile = StringIO.StringIO(self.packet)
+ self.wfile = StringIO.StringIO(self.packet)
def finish(self):
- self.socket.send(self.wfile.getvalue())
+ self.socket.send(self.wfile.getvalue())
def __init__(self): self.data = {}
def __repr__(self): return repr(self.data)
def __cmp__(self, dict):
- if type(dict) == type(self.data):
- return cmp(self.data, dict)
- else:
- return cmp(self.data, dict.data)
+ if type(dict) == type(self.data):
+ return cmp(self.data, dict)
+ else:
+ return cmp(self.data, dict.data)
def __len__(self): return len(self.data)
def __getitem__(self, key): return self.data[key]
def __setitem__(self, key, item): self.data[key] = item
def __delitem__(self, key): del self.data[key]
def clear(self): return self.data.clear()
def copy(self):
- import copy
- return copy.copy(self)
+ import copy
+ return copy.copy(self)
def keys(self): return self.data.keys()
def items(self): return self.data.items()
def values(self): return self.data.values()
def has_key(self, key): return self.data.has_key(key)
def update(self, other):
- if type(other) is type(self.data):
- self.data.update(other)
- else:
- for k, v in other.items():
- self.data[k] = v
+ if type(other) is type(self.data):
+ self.data.update(other)
+ else:
+ for k, v in other.items():
+ self.data[k] = v
def get(self, key, failobj=None):
- if self.data.has_key(key):
- return self.data[key]
- else:
- return failobj
+ if self.data.has_key(key):
+ return self.data[key]
+ else:
+ return failobj
telling the client what kind of data is following. Python code to
generate a minimal header section looks like this:
- print "Content-type: text/html" # HTML is following
- print # blank line, end of headers
+ print "Content-type: text/html" # HTML is following
+ print # blank line, end of headers
The second section is usually HTML, which allows the client software
to display nicely formatted text with header, in-line images, etc.
Here's Python code that prints a simple piece of HTML:
- print "<TITLE>CGI script output</TITLE>"
- print "<H1>This is my first CGI script</H1>"
- print "Hello, world!"
+ print "<TITLE>CGI script output</TITLE>"
+ print "<H1>This is my first CGI script</H1>"
+ print "Hello, world!"
It may not be fully legal HTML according to the letter of the
standard, but any browser will understand it.
Content-type header and blank line have already been printed) checks that
the fields "name" and "addr" are both set to a non-empty string:
- form = cgi.FieldStorage()
- form_ok = 0
- if form.has_key("name") and form.has_key("addr"):
- if form["name"].value != "" and form["addr"].value != "":
- form_ok = 1
- if not form_ok:
- print "<H1>Error</H1>"
- print "Please fill in the name and addr fields."
- return
- ...further form processing here...
+ form = cgi.FieldStorage()
+ form_ok = 0
+ if form.has_key("name") and form.has_key("addr"):
+ if form["name"].value != "" and form["addr"].value != "":
+ form_ok = 1
+ if not form_ok:
+ print "<H1>Error</H1>"
+ print "Please fill in the name and addr fields."
+ return
+ ...further form processing here...
Here the fields, accessed through form[key], are themselves instances
of FieldStorage (or MiniFieldStorage, depending on the form encoding).
a single instance or a list of instances. For example, here's code
that concatenates any number of username fields, separated by commas:
- username = form["username"]
- if type(username) is type([]):
- # Multiple username fields specified
- usernames = ""
- for item in username:
- if usernames:
- # Next item -- insert comma
- usernames = usernames + "," + item.value
- else:
- # First item -- don't insert comma
- usernames = item.value
- else:
- # Single username field specified
- usernames = username.value
+ username = form["username"]
+ if type(username) is type([]):
+ # Multiple username fields specified
+ usernames = ""
+ for item in username:
+ if usernames:
+ # Next item -- insert comma
+ usernames = usernames + "," + item.value
+ else:
+ # First item -- don't insert comma
+ usernames = item.value
+ else:
+ # Single username field specified
+ usernames = username.value
If a field represents an uploaded file, the value attribute reads the
entire file in memory as a string. This may not be what you want. You can
file attribute. You can then read the data at leasure from the file
attribute:
- fileitem = form["userfile"]
- if fileitem.file:
- # It's an uploaded file; count lines
- linecount = 0
- while 1:
- line = fileitem.file.readline()
- if not line: break
- linecount = linecount + 1
+ fileitem = form["userfile"]
+ if fileitem.file:
+ # It's an uploaded file; count lines
+ linecount = 0
+ while 1:
+ line = fileitem.file.readline()
+ if not line: break
+ linecount = linecount + 1
The file upload draft standard entertains the possibility of uploading
multiple files from one field (using a recursive multipart/*
that the first line of the script contains #! starting in column 1
followed by the pathname of the Python interpreter, for instance:
- #! /usr/local/bin/python
+ #! /usr/local/bin/python
Make sure the Python interpreter exists and is executable by "others".
default module search path, you can change the path in your script,
before importing other modules, e.g.:
- import sys
- sys.path.insert(0, "/usr/home/joe/lib/python")
- sys.path.insert(0, "/usr/local/lib/python")
+ import sys
+ sys.path.insert(0, "/usr/home/joe/lib/python")
+ sys.path.insert(0, "/usr/local/lib/python")
This way, the directory inserted last will be searched first!
in the standard cgi-bin directory, it should be possible to send it a
request by entering a URL into your browser of the form:
- http://yourhostname/cgi-bin/cgi.py?name=Joe+Blow&addr=At+Home
+ http://yourhostname/cgi-bin/cgi.py?name=Joe+Blow&addr=At+Home
If this gives an error of type 404, the server cannot find the script
-- perhaps you need to install it in a different directory. If it
The next step could be to call the cgi module's test() function from
your script: replace its main code with the single statement
- cgi.test()
-
+ cgi.test()
+
This should produce the same results as those gotten from installing
the cgi.py file itself.
be printed. The test() function below in this module is an example.
Here are the rules:
- 1. Import the traceback module (before entering the
- try-except!)
-
- 2. Make sure you finish printing the headers and the blank
- line early
-
- 3. Assign sys.stderr to sys.stdout
-
- 3. Wrap all remaining code in a try-except statement
-
- 4. In the except clause, call traceback.print_exc()
+ 1. Import the traceback module (before entering the
+ try-except!)
+
+ 2. Make sure you finish printing the headers and the blank
+ line early
+
+ 3. Assign sys.stderr to sys.stdout
+
+ 3. Wrap all remaining code in a try-except statement
+
+ 4. In the except clause, call traceback.print_exc()
For example:
- import sys
- import traceback
- print "Content-type: text/html"
- print
- sys.stderr = sys.stdout
- try:
- ...your code here...
- except:
- print "\n\n<PRE>"
- traceback.print_exc()
+ import sys
+ import traceback
+ print "Content-type: text/html"
+ print
+ sys.stderr = sys.stdout
+ try:
+ ...your code here...
+ except:
+ print "\n\n<PRE>"
+ traceback.print_exc()
Notes: The assignment to sys.stderr is needed because the traceback
prints to sys.stderr. The print "\n\n<PRE>" statement is necessary to
module, you can use an even more robust approach (which only uses
built-in modules):
- import sys
- sys.stderr = sys.stdout
- print "Content-type: text/plain"
- print
- ...your code here...
+ import sys
+ sys.stderr = sys.stdout
+ print "Content-type: text/plain"
+ print
+ ...your code here...
This relies on the Python interpreter to print the traceback. The
content type of the output is set to plain text, which disables all
# Logging support
# ===============
-logfile = "" # Filename to log to, if not empty
-logfp = None # File object to log to, if not None
+logfile = "" # Filename to log to, if not empty
+logfp = None # File object to log to, if not None
def initlog(*allargs):
"""Write a log message, if there is a log file.
"""
global logfp, log
if logfile and not logfp:
- try:
- logfp = open(logfile, "a")
- except IOError:
- pass
+ try:
+ logfp = open(logfile, "a")
+ except IOError:
+ pass
if not logfp:
- log = nolog
+ log = nolog
else:
- log = dolog
+ log = dolog
apply(log, allargs)
def dolog(fmt, *args):
"""Dummy function, assigned to log when logging is disabled."""
pass
-log = initlog # The current logging function
+log = initlog # The current logging function
# Parsing functions
fp : file pointer; default: sys.stdin
- environ : environment dictionary; default: os.environ
+ environ : environment dictionary; default: os.environ
keep_blank_values: flag indicating whether blank values in
URL encoded forms should be treated as blank strings.
A true value inicates that blanks should be retained as
blank strings. The default false value indicates that
- blank values are to be ignored and treated as if they were
- not included.
+ blank values are to be ignored and treated as if they were
+ not included.
- strict_parsing: flag indicating what to do with parsing errors.
- If false (the default), errors are silently ignored.
- If true, errors raise a ValueError exception.
+ strict_parsing: flag indicating what to do with parsing errors.
+ If false (the default), errors are silently ignored.
+ If true, errors raise a ValueError exception.
"""
if not fp:
- fp = sys.stdin
+ fp = sys.stdin
if not environ.has_key('REQUEST_METHOD'):
- environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
+ environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone
if environ['REQUEST_METHOD'] == 'POST':
- ctype, pdict = parse_header(environ['CONTENT_TYPE'])
- if ctype == 'multipart/form-data':
- return parse_multipart(fp, pdict)
- elif ctype == 'application/x-www-form-urlencoded':
- clength = string.atoi(environ['CONTENT_LENGTH'])
- if maxlen and clength > maxlen:
- raise ValueError, 'Maximum content length exceeded'
- qs = fp.read(clength)
- else:
- qs = '' # Unknown content-type
- if environ.has_key('QUERY_STRING'):
- if qs: qs = qs + '&'
- qs = qs + environ['QUERY_STRING']
- elif sys.argv[1:]:
- if qs: qs = qs + '&'
- qs = qs + sys.argv[1]
- environ['QUERY_STRING'] = qs # XXX Shouldn't, really
+ ctype, pdict = parse_header(environ['CONTENT_TYPE'])
+ if ctype == 'multipart/form-data':
+ return parse_multipart(fp, pdict)
+ elif ctype == 'application/x-www-form-urlencoded':
+ clength = string.atoi(environ['CONTENT_LENGTH'])
+ if maxlen and clength > maxlen:
+ raise ValueError, 'Maximum content length exceeded'
+ qs = fp.read(clength)
+ else:
+ qs = '' # Unknown content-type
+ if environ.has_key('QUERY_STRING'):
+ if qs: qs = qs + '&'
+ qs = qs + environ['QUERY_STRING']
+ elif sys.argv[1:]:
+ if qs: qs = qs + '&'
+ qs = qs + sys.argv[1]
+ environ['QUERY_STRING'] = qs # XXX Shouldn't, really
elif environ.has_key('QUERY_STRING'):
- qs = environ['QUERY_STRING']
+ qs = environ['QUERY_STRING']
else:
- if sys.argv[1:]:
- qs = sys.argv[1]
- else:
- qs = ""
- environ['QUERY_STRING'] = qs # XXX Shouldn't, really
+ if sys.argv[1:]:
+ qs = sys.argv[1]
+ else:
+ qs = ""
+ environ['QUERY_STRING'] = qs # XXX Shouldn't, really
return parse_qs(qs, keep_blank_values, strict_parsing)
Arguments:
- qs: URL-encoded query string to be parsed
+ qs: URL-encoded query string to be parsed
keep_blank_values: flag indicating whether blank values in
URL encoded queries should be treated as blank strings.
A true value inicates that blanks should be retained as
blank strings. The default false value indicates that
- blank values are to be ignored and treated as if they were
- not included.
+ blank values are to be ignored and treated as if they were
+ not included.
- strict_parsing: flag indicating what to do with parsing errors.
- If false (the default), errors are silently ignored.
- If true, errors raise a ValueError exception.
+ strict_parsing: flag indicating what to do with parsing errors.
+ If false (the default), errors are silently ignored.
+ If true, errors raise a ValueError exception.
"""
name_value_pairs = string.splitfields(qs, '&')
dict = {}
for name_value in name_value_pairs:
- nv = string.splitfields(name_value, '=')
- if len(nv) != 2:
- if strict_parsing:
- raise ValueError, "bad query field: %s" % `name_value`
- continue
- name = urllib.unquote(string.replace(nv[0], '+', ' '))
- value = urllib.unquote(string.replace(nv[1], '+', ' '))
+ nv = string.splitfields(name_value, '=')
+ if len(nv) != 2:
+ if strict_parsing:
+ raise ValueError, "bad query field: %s" % `name_value`
+ continue
+ name = urllib.unquote(string.replace(nv[0], '+', ' '))
+ value = urllib.unquote(string.replace(nv[1], '+', ' '))
if len(value) or keep_blank_values:
- if dict.has_key (name):
- dict[name].append(value)
- else:
- dict[name] = [value]
+ if dict.has_key (name):
+ dict[name].append(value)
+ else:
+ dict[name] = [value]
return dict
"""
if pdict.has_key('boundary'):
- boundary = pdict['boundary']
+ boundary = pdict['boundary']
else:
- boundary = ""
+ boundary = ""
nextpart = "--" + boundary
lastpart = "--" + boundary + "--"
partdict = {}
terminator = ""
while terminator != lastpart:
- bytes = -1
- data = None
- if terminator:
- # At start of next part. Read headers first.
- headers = mimetools.Message(fp)
- clength = headers.getheader('content-length')
- if clength:
- try:
- bytes = string.atoi(clength)
- except string.atoi_error:
- pass
- if bytes > 0:
- if maxlen and bytes > maxlen:
- raise ValueError, 'Maximum content length exceeded'
- data = fp.read(bytes)
- else:
- data = ""
- # Read lines until end of part.
- lines = []
- while 1:
- line = fp.readline()
- if not line:
- terminator = lastpart # End outer loop
- break
- if line[:2] == "--":
- terminator = string.strip(line)
- if terminator in (nextpart, lastpart):
- break
- lines.append(line)
- # Done with part.
- if data is None:
- continue
- if bytes < 0:
- if lines:
- # Strip final line terminator
- line = lines[-1]
- if line[-2:] == "\r\n":
- line = line[:-2]
- elif line[-1:] == "\n":
- line = line[:-1]
- lines[-1] = line
- data = string.joinfields(lines, "")
- line = headers['content-disposition']
- if not line:
- continue
- key, params = parse_header(line)
- if key != 'form-data':
- continue
- if params.has_key('name'):
- name = params['name']
- else:
- continue
- if partdict.has_key(name):
- partdict[name].append(data)
- else:
- partdict[name] = [data]
+ bytes = -1
+ data = None
+ if terminator:
+ # At start of next part. Read headers first.
+ headers = mimetools.Message(fp)
+ clength = headers.getheader('content-length')
+ if clength:
+ try:
+ bytes = string.atoi(clength)
+ except string.atoi_error:
+ pass
+ if bytes > 0:
+ if maxlen and bytes > maxlen:
+ raise ValueError, 'Maximum content length exceeded'
+ data = fp.read(bytes)
+ else:
+ data = ""
+ # Read lines until end of part.
+ lines = []
+ while 1:
+ line = fp.readline()
+ if not line:
+ terminator = lastpart # End outer loop
+ break
+ if line[:2] == "--":
+ terminator = string.strip(line)
+ if terminator in (nextpart, lastpart):
+ break
+ lines.append(line)
+ # Done with part.
+ if data is None:
+ continue
+ if bytes < 0:
+ if lines:
+ # Strip final line terminator
+ line = lines[-1]
+ if line[-2:] == "\r\n":
+ line = line[:-2]
+ elif line[-1:] == "\n":
+ line = line[:-1]
+ lines[-1] = line
+ data = string.joinfields(lines, "")
+ line = headers['content-disposition']
+ if not line:
+ continue
+ key, params = parse_header(line)
+ if key != 'form-data':
+ continue
+ if params.has_key('name'):
+ name = params['name']
+ else:
+ continue
+ if partdict.has_key(name):
+ partdict[name].append(data)
+ else:
+ partdict[name] = [data]
return partdict
del plist[0]
pdict = {}
for p in plist:
- i = string.find(p, '=')
- if i >= 0:
- name = string.lower(string.strip(p[:i]))
- value = string.strip(p[i+1:])
- if len(value) >= 2 and value[0] == value[-1] == '"':
- value = value[1:-1]
- pdict[name] = value
+ i = string.find(p, '=')
+ if i >= 0:
+ name = string.lower(string.strip(p[:i]))
+ value = string.strip(p[i+1:])
+ if len(value) >= 2 and value[0] == value[-1] == '"':
+ value = value[1:-1]
+ pdict[name] = value
return key, pdict
headers = {}
def __init__(self, name, value):
- """Constructor from field name and value."""
- self.name = name
- self.value = value
+ """Constructor from field name and value."""
+ self.name = name
+ self.value = value
# self.file = StringIO(value)
def __repr__(self):
- """Return printable representation."""
- return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
+ """Return printable representation."""
+ return "MiniFieldStorage(%s, %s)" % (`self.name`, `self.value`)
class FieldStorage:
name: the field name, if specified; otherwise None
filename: the filename, if specified; otherwise None; this is the
- client side filename, *not* the file name on which it is
- stored (that's a temporary file you don't deal with)
+ client side filename, *not* the file name on which it is
+ stored (that's a temporary file you don't deal with)
value: the value as a *string*; for file uploads, this
- transparently reads the file every time you request the value
+ transparently reads the file every time you request the value
file: the file(-like) object from which you can read the data;
- None if the data is stored a simple string
+ None if the data is stored a simple string
type: the content-type, or None if not specified
type_options: dictionary of options specified on the content-type
- line
+ line
disposition: content-disposition, or None if not specified
disposition_options: dictionary of corresponding options
headers: a dictionary(-like) object (sometimes rfc822.Message or a
- subclass thereof) containing *all* headers
+ subclass thereof) containing *all* headers
The class is subclassable, mostly for the purpose of overriding
the make_file() method, which is called internally to come up with
"""
def __init__(self, fp=None, headers=None, outerboundary="",
- environ=os.environ, keep_blank_values=0, strict_parsing=0):
- """Constructor. Read multipart/* until last part.
+ environ=os.environ, keep_blank_values=0, strict_parsing=0):
+ """Constructor. Read multipart/* until last part.
- Arguments, all optional:
+ Arguments, all optional:
- fp : file pointer; default: sys.stdin
+ fp : file pointer; default: sys.stdin
- headers : header dictionary-like object; default:
- taken from environ as per CGI spec
+ headers : header dictionary-like object; default:
+ taken from environ as per CGI spec
outerboundary : terminating multipart boundary
- (for internal use only)
+ (for internal use only)
- environ : environment dictionary; default: os.environ
+ environ : environment dictionary; default: os.environ
keep_blank_values: flag indicating whether blank values in
URL encoded forms should be treated as blank strings.
A true value inicates that blanks should be retained as
blank strings. The default false value indicates that
- blank values are to be ignored and treated as if they were
- not included.
-
- strict_parsing: flag indicating what to do with parsing errors.
- If false (the default), errors are silently ignored.
- If true, errors raise a ValueError exception.
-
- """
- method = 'GET'
- self.keep_blank_values = keep_blank_values
- self.strict_parsing = strict_parsing
- if environ.has_key('REQUEST_METHOD'):
- method = string.upper(environ['REQUEST_METHOD'])
- if not fp and method == 'GET':
- if environ.has_key('QUERY_STRING'):
- qs = environ['QUERY_STRING']
- elif sys.argv[1:]:
- qs = sys.argv[1]
- else:
- qs = ""
- fp = StringIO(qs)
- if headers is None:
- headers = {'content-type':
- "application/x-www-form-urlencoded"}
- if headers is None:
- headers = {}
- if environ.has_key('CONTENT_TYPE'):
- headers['content-type'] = environ['CONTENT_TYPE']
- if environ.has_key('CONTENT_LENGTH'):
- headers['content-length'] = environ['CONTENT_LENGTH']
- self.fp = fp or sys.stdin
- self.headers = headers
- self.outerboundary = outerboundary
-
- # Process content-disposition header
- cdisp, pdict = "", {}
- if self.headers.has_key('content-disposition'):
- cdisp, pdict = parse_header(self.headers['content-disposition'])
- self.disposition = cdisp
- self.disposition_options = pdict
- self.name = None
- if pdict.has_key('name'):
- self.name = pdict['name']
- self.filename = None
- if pdict.has_key('filename'):
- self.filename = pdict['filename']
-
- # Process content-type header
- ctype, pdict = "text/plain", {}
- if self.headers.has_key('content-type'):
- ctype, pdict = parse_header(self.headers['content-type'])
- self.type = ctype
- self.type_options = pdict
- self.innerboundary = ""
- if pdict.has_key('boundary'):
- self.innerboundary = pdict['boundary']
- clen = -1
- if self.headers.has_key('content-length'):
- try:
- clen = string.atoi(self.headers['content-length'])
- except:
- pass
- if maxlen and clen > maxlen:
- raise ValueError, 'Maximum content length exceeded'
- self.length = clen
-
- self.list = self.file = None
- self.done = 0
- self.lines = []
- if ctype == 'application/x-www-form-urlencoded':
- self.read_urlencoded()
- elif ctype[:10] == 'multipart/':
- self.read_multi()
- else:
- self.read_single()
+ blank values are to be ignored and treated as if they were
+ not included.
+
+ strict_parsing: flag indicating what to do with parsing errors.
+ If false (the default), errors are silently ignored.
+ If true, errors raise a ValueError exception.
+
+ """
+ method = 'GET'
+ self.keep_blank_values = keep_blank_values
+ self.strict_parsing = strict_parsing
+ if environ.has_key('REQUEST_METHOD'):
+ method = string.upper(environ['REQUEST_METHOD'])
+ if not fp and method == 'GET':
+ if environ.has_key('QUERY_STRING'):
+ qs = environ['QUERY_STRING']
+ elif sys.argv[1:]:
+ qs = sys.argv[1]
+ else:
+ qs = ""
+ fp = StringIO(qs)
+ if headers is None:
+ headers = {'content-type':
+ "application/x-www-form-urlencoded"}
+ if headers is None:
+ headers = {}
+ if environ.has_key('CONTENT_TYPE'):
+ headers['content-type'] = environ['CONTENT_TYPE']
+ if environ.has_key('CONTENT_LENGTH'):
+ headers['content-length'] = environ['CONTENT_LENGTH']
+ self.fp = fp or sys.stdin
+ self.headers = headers
+ self.outerboundary = outerboundary
+
+ # Process content-disposition header
+ cdisp, pdict = "", {}
+ if self.headers.has_key('content-disposition'):
+ cdisp, pdict = parse_header(self.headers['content-disposition'])
+ self.disposition = cdisp
+ self.disposition_options = pdict
+ self.name = None
+ if pdict.has_key('name'):
+ self.name = pdict['name']
+ self.filename = None
+ if pdict.has_key('filename'):
+ self.filename = pdict['filename']
+
+ # Process content-type header
+ ctype, pdict = "text/plain", {}
+ if self.headers.has_key('content-type'):
+ ctype, pdict = parse_header(self.headers['content-type'])
+ self.type = ctype
+ self.type_options = pdict
+ self.innerboundary = ""
+ if pdict.has_key('boundary'):
+ self.innerboundary = pdict['boundary']
+ clen = -1
+ if self.headers.has_key('content-length'):
+ try:
+ clen = string.atoi(self.headers['content-length'])
+ except:
+ pass
+ if maxlen and clen > maxlen:
+ raise ValueError, 'Maximum content length exceeded'
+ self.length = clen
+
+ self.list = self.file = None
+ self.done = 0
+ self.lines = []
+ if ctype == 'application/x-www-form-urlencoded':
+ self.read_urlencoded()
+ elif ctype[:10] == 'multipart/':
+ self.read_multi()
+ else:
+ self.read_single()
def __repr__(self):
- """Return a printable representation."""
- return "FieldStorage(%s, %s, %s)" % (
- `self.name`, `self.filename`, `self.value`)
+ """Return a printable representation."""
+ return "FieldStorage(%s, %s, %s)" % (
+ `self.name`, `self.filename`, `self.value`)
def __getattr__(self, name):
- if name != 'value':
- raise AttributeError, name
- if self.file:
- self.file.seek(0)
- value = self.file.read()
- self.file.seek(0)
- elif self.list is not None:
- value = self.list
- else:
- value = None
- return value
+ if name != 'value':
+ raise AttributeError, name
+ if self.file:
+ self.file.seek(0)
+ value = self.file.read()
+ self.file.seek(0)
+ elif self.list is not None:
+ value = self.list
+ else:
+ value = None
+ return value
def __getitem__(self, key):
- """Dictionary style indexing."""
- if self.list is None:
- raise TypeError, "not indexable"
- found = []
- for item in self.list:
- if item.name == key: found.append(item)
- if not found:
- raise KeyError, key
- if len(found) == 1:
- return found[0]
- else:
- return found
+ """Dictionary style indexing."""
+ if self.list is None:
+ raise TypeError, "not indexable"
+ found = []
+ for item in self.list:
+ if item.name == key: found.append(item)
+ if not found:
+ raise KeyError, key
+ if len(found) == 1:
+ return found[0]
+ else:
+ return found
def keys(self):
- """Dictionary style keys() method."""
- if self.list is None:
- raise TypeError, "not indexable"
- keys = []
- for item in self.list:
- if item.name not in keys: keys.append(item.name)
- return keys
+ """Dictionary style keys() method."""
+ if self.list is None:
+ raise TypeError, "not indexable"
+ keys = []
+ for item in self.list:
+ if item.name not in keys: keys.append(item.name)
+ return keys
def has_key(self, key):
- """Dictionary style has_key() method."""
- if self.list is None:
- raise TypeError, "not indexable"
- for item in self.list:
- if item.name == key: return 1
- return 0
+ """Dictionary style has_key() method."""
+ if self.list is None:
+ raise TypeError, "not indexable"
+ for item in self.list:
+ if item.name == key: return 1
+ return 0
def __len__(self):
- """Dictionary style len(x) support."""
- return len(self.keys())
+ """Dictionary style len(x) support."""
+ return len(self.keys())
def read_urlencoded(self):
- """Internal: read data in query string format."""
- qs = self.fp.read(self.length)
- dict = parse_qs(qs, self.keep_blank_values, self.strict_parsing)
- self.list = []
- for key, valuelist in dict.items():
- for value in valuelist:
- self.list.append(MiniFieldStorage(key, value))
- self.skip_lines()
+ """Internal: read data in query string format."""
+ qs = self.fp.read(self.length)
+ dict = parse_qs(qs, self.keep_blank_values, self.strict_parsing)
+ self.list = []
+ for key, valuelist in dict.items():
+ for value in valuelist:
+ self.list.append(MiniFieldStorage(key, value))
+ self.skip_lines()
def read_multi(self):
- """Internal: read a part that is itself multipart."""
- self.list = []
- part = self.__class__(self.fp, {}, self.innerboundary)
- # Throw first part away
- while not part.done:
- headers = rfc822.Message(self.fp)
- part = self.__class__(self.fp, headers, self.innerboundary)
- self.list.append(part)
- self.skip_lines()
+ """Internal: read a part that is itself multipart."""
+ self.list = []
+ part = self.__class__(self.fp, {}, self.innerboundary)
+ # Throw first part away
+ while not part.done:
+ headers = rfc822.Message(self.fp)
+ part = self.__class__(self.fp, headers, self.innerboundary)
+ self.list.append(part)
+ self.skip_lines()
def read_single(self):
- """Internal: read an atomic part."""
- if self.length >= 0:
- self.read_binary()
- self.skip_lines()
- else:
- self.read_lines()
- self.file.seek(0)
+ """Internal: read an atomic part."""
+ if self.length >= 0:
+ self.read_binary()
+ self.skip_lines()
+ else:
+ self.read_lines()
+ self.file.seek(0)
- bufsize = 8*1024 # I/O buffering size for copy to file
+ bufsize = 8*1024 # I/O buffering size for copy to file
def read_binary(self):
- """Internal: read binary data."""
- self.file = self.make_file('b')
- todo = self.length
- if todo >= 0:
- while todo > 0:
- data = self.fp.read(min(todo, self.bufsize))
- if not data:
- self.done = -1
- break
- self.file.write(data)
- todo = todo - len(data)
+ """Internal: read binary data."""
+ self.file = self.make_file('b')
+ todo = self.length
+ if todo >= 0:
+ while todo > 0:
+ data = self.fp.read(min(todo, self.bufsize))
+ if not data:
+ self.done = -1
+ break
+ self.file.write(data)
+ todo = todo - len(data)
def read_lines(self):
- """Internal: read lines until EOF or outerboundary."""
- self.file = self.make_file('')
- if self.outerboundary:
- self.read_lines_to_outerboundary()
- else:
- self.read_lines_to_eof()
+ """Internal: read lines until EOF or outerboundary."""
+ self.file = self.make_file('')
+ if self.outerboundary:
+ self.read_lines_to_outerboundary()
+ else:
+ self.read_lines_to_eof()
def read_lines_to_eof(self):
- """Internal: read lines until EOF."""
- while 1:
- line = self.fp.readline()
- if not line:
- self.done = -1
- break
- self.lines.append(line)
- self.file.write(line)
+ """Internal: read lines until EOF."""
+ while 1:
+ line = self.fp.readline()
+ if not line:
+ self.done = -1
+ break
+ self.lines.append(line)
+ self.file.write(line)
def read_lines_to_outerboundary(self):
- """Internal: read lines until outerboundary."""
- next = "--" + self.outerboundary
- last = next + "--"
- delim = ""
- while 1:
- line = self.fp.readline()
- if not line:
- self.done = -1
- break
- self.lines.append(line)
- if line[:2] == "--":
- strippedline = string.strip(line)
- if strippedline == next:
- break
- if strippedline == last:
- self.done = 1
- break
- odelim = delim
- if line[-2:] == "\r\n":
- delim = "\r\n"
- line = line[:-2]
- elif line[-1] == "\n":
- delim = "\n"
- line = line[:-1]
- else:
- delim = ""
- self.file.write(odelim + line)
+ """Internal: read lines until outerboundary."""
+ next = "--" + self.outerboundary
+ last = next + "--"
+ delim = ""
+ while 1:
+ line = self.fp.readline()
+ if not line:
+ self.done = -1
+ break
+ self.lines.append(line)
+ if line[:2] == "--":
+ strippedline = string.strip(line)
+ if strippedline == next:
+ break
+ if strippedline == last:
+ self.done = 1
+ break
+ odelim = delim
+ if line[-2:] == "\r\n":
+ delim = "\r\n"
+ line = line[:-2]
+ elif line[-1] == "\n":
+ delim = "\n"
+ line = line[:-1]
+ else:
+ delim = ""
+ self.file.write(odelim + line)
def skip_lines(self):
- """Internal: skip lines until outer boundary if defined."""
- if not self.outerboundary or self.done:
- return
- next = "--" + self.outerboundary
- last = next + "--"
- while 1:
- line = self.fp.readline()
- if not line:
- self.done = -1
- break
- self.lines.append(line)
- if line[:2] == "--":
- strippedline = string.strip(line)
- if strippedline == next:
- break
- if strippedline == last:
- self.done = 1
- break
+ """Internal: skip lines until outer boundary if defined."""
+ if not self.outerboundary or self.done:
+ return
+ next = "--" + self.outerboundary
+ last = next + "--"
+ while 1:
+ line = self.fp.readline()
+ if not line:
+ self.done = -1
+ break
+ self.lines.append(line)
+ if line[:2] == "--":
+ strippedline = string.strip(line)
+ if strippedline == next:
+ break
+ if strippedline == last:
+ self.done = 1
+ break
def make_file(self, binary=None):
- """Overridable: return a readable & writable file.
+ """Overridable: return a readable & writable file.
- The file will be used as follows:
- - data is written to it
- - seek(0)
- - data is read from it
+ The file will be used as follows:
+ - data is written to it
+ - seek(0)
+ - data is read from it
- The 'binary' argument is unused -- the file is always opened
- in binary mode.
+ The 'binary' argument is unused -- the file is always opened
+ in binary mode.
- This version opens a temporary file for reading and writing,
- and immediately deletes (unlinks) it. The trick (on Unix!) is
- that the file can still be used, but it can't be opened by
- another process, and it will automatically be deleted when it
- is closed or when the current process terminates.
+ This version opens a temporary file for reading and writing,
+ and immediately deletes (unlinks) it. The trick (on Unix!) is
+ that the file can still be used, but it can't be opened by
+ another process, and it will automatically be deleted when it
+ is closed or when the current process terminates.
- If you want a more permanent file, you derive a class which
- overrides this method. If you want a visible temporary file
- that is nevertheless automatically deleted when the script
- terminates, try defining a __del__ method in a derived class
- which unlinks the temporary files you have created.
+ If you want a more permanent file, you derive a class which
+ overrides this method. If you want a visible temporary file
+ that is nevertheless automatically deleted when the script
+ terminates, try defining a __del__ method in a derived class
+ which unlinks the temporary files you have created.
- """
- import tempfile
- return tempfile.TemporaryFile("w+b")
-
+ """
+ import tempfile
+ return tempfile.TemporaryFile("w+b")
+
# Backwards Compatibility Classes
"""
def __init__(self, environ=os.environ):
self.dict = parse(environ=environ)
- self.query_string = environ['QUERY_STRING']
+ self.query_string = environ['QUERY_STRING']
def __getitem__(self,key):
- return self.dict[key]
+ return self.dict[key]
def keys(self):
- return self.dict.keys()
+ return self.dict.keys()
def has_key(self, key):
- return self.dict.has_key(key)
+ return self.dict.has_key(key)
def values(self):
- return self.dict.values()
+ return self.dict.values()
def items(self):
- return self.dict.items()
+ return self.dict.items()
def __len__( self ):
- return len(self.dict)
+ return len(self.dict)
class SvFormContentDict(FormContentDict):
"""
def __getitem__(self, key):
- if len(self.dict[key]) > 1:
- raise IndexError, 'expecting a single value'
- return self.dict[key][0]
+ if len(self.dict[key]) > 1:
+ raise IndexError, 'expecting a single value'
+ return self.dict[key][0]
def getlist(self, key):
- return self.dict[key]
+ return self.dict[key]
def values(self):
- lis = []
- for each in self.dict.values():
- if len( each ) == 1 :
- lis.append(each[0])
- else: lis.append(each)
- return lis
+ lis = []
+ for each in self.dict.values():
+ if len( each ) == 1 :
+ lis.append(each[0])
+ else: lis.append(each)
+ return lis
def items(self):
- lis = []
- for key,value in self.dict.items():
- if len(value) == 1 :
- lis.append((key, value[0]))
- else: lis.append((key, value))
- return lis
+ lis = []
+ for key,value in self.dict.items():
+ if len(value) == 1 :
+ lis.append((key, value[0]))
+ else: lis.append((key, value))
+ return lis
class InterpFormContentDict(SvFormContentDict):
"""This class is present for backwards compatibility only."""
def __getitem__( self, key ):
- v = SvFormContentDict.__getitem__( self, key )
- if v[0] in string.digits+'+-.' :
- try: return string.atoi( v )
- except ValueError:
- try: return string.atof( v )
- except ValueError: pass
- return string.strip(v)
+ v = SvFormContentDict.__getitem__( self, key )
+ if v[0] in string.digits+'+-.' :
+ try: return string.atoi( v )
+ except ValueError:
+ try: return string.atof( v )
+ except ValueError: pass
+ return string.strip(v)
def values( self ):
- lis = []
- for key in self.keys():
- try:
- lis.append( self[key] )
- except IndexError:
- lis.append( self.dict[key] )
- return lis
+ lis = []
+ for key in self.keys():
+ try:
+ lis.append( self[key] )
+ except IndexError:
+ lis.append( self.dict[key] )
+ return lis
def items( self ):
- lis = []
- for key in self.keys():
- try:
- lis.append( (key, self[key]) )
- except IndexError:
- lis.append( (key, self.dict[key]) )
- return lis
+ lis = []
+ for key in self.keys():
+ try:
+ lis.append( (key, self[key]) )
+ except IndexError:
+ lis.append( (key, self.dict[key]) )
+ return lis
class FormContent(FormContentDict):
"""This class is present for backwards compatibility only."""
def values(self, key):
- if self.dict.has_key(key) :return self.dict[key]
- else: return None
+ if self.dict.has_key(key) :return self.dict[key]
+ else: return None
def indexed_value(self, key, location):
- if self.dict.has_key(key):
- if len (self.dict[key]) > location:
- return self.dict[key][location]
- else: return None
- else: return None
+ if self.dict.has_key(key):
+ if len (self.dict[key]) > location:
+ return self.dict[key][location]
+ else: return None
+ else: return None
def value(self, key):
- if self.dict.has_key(key): return self.dict[key][0]
- else: return None
+ if self.dict.has_key(key): return self.dict[key][0]
+ else: return None
def length(self, key):
- return len(self.dict[key])
+ return len(self.dict[key])
def stripped(self, key):
- if self.dict.has_key(key): return string.strip(self.dict[key][0])
- else: return None
+ if self.dict.has_key(key): return string.strip(self.dict[key][0])
+ else: return None
def pars(self):
- return self.dict
+ return self.dict
# Test/debug code
print
sys.stderr = sys.stdout
try:
- form = FieldStorage() # Replace with other classes to test those
- print_form(form)
+ form = FieldStorage() # Replace with other classes to test those
+ print_form(form)
print_environ(environ)
- print_directory()
- print_arguments()
- print_environ_usage()
- def f():
- exec "testing print_exception() -- <I>italics?</I>"
- def g(f=f):
- f()
- print "<H3>What follows is a test, not an actual exception:</H3>"
- g()
+ print_directory()
+ print_arguments()
+ print_environ_usage()
+ def f():
+ exec "testing print_exception() -- <I>italics?</I>"
+ def g(f=f):
+ f()
+ print "<H3>What follows is a test, not an actual exception:</H3>"
+ g()
except:
- print_exception()
+ print_exception()
# Second try with a small maxlen...
global maxlen
maxlen = 50
try:
- form = FieldStorage() # Replace with other classes to test those
- print_form(form)
- print_environ(environ)
- print_directory()
- print_arguments()
- print_environ_usage()
+ form = FieldStorage() # Replace with other classes to test those
+ print_form(form)
+ print_environ(environ)
+ print_directory()
+ print_arguments()
+ print_environ_usage()
except:
- print_exception()
+ print_exception()
def print_exception(type=None, value=None, tb=None, limit=None):
if type is None:
- type, value, tb = sys.exc_info()
+ type, value, tb = sys.exc_info()
import traceback
print
print "<H3>Traceback (innermost last):</H3>"
list = traceback.format_tb(tb, limit) + \
- traceback.format_exception_only(type, value)
+ traceback.format_exception_only(type, value)
print "<PRE>%s<B>%s</B></PRE>" % (
- escape(string.join(list[:-1], "")),
- escape(list[-1]),
- )
+ escape(string.join(list[:-1], "")),
+ escape(list[-1]),
+ )
del tb
def print_environ(environ=os.environ):
print "<H3>Shell Environment:</H3>"
print "<DL>"
for key in keys:
- print "<DT>", escape(key), "<DD>", escape(environ[key])
+ print "<DT>", escape(key), "<DD>", escape(environ[key])
print "</DL>"
print
print "<H3>Form Contents:</H3>"
print "<DL>"
for key in keys:
- print "<DT>" + escape(key) + ":",
- value = form[key]
- print "<i>" + escape(`type(value)`) + "</i>"
- print "<DD>" + escape(`value`)
+ print "<DT>" + escape(key) + ":",
+ value = form[key]
+ print "<i>" + escape(`type(value)`) + "</i>"
+ print "<DD>" + escape(`value`)
print "</DL>"
print
print
print "<H3>Current Working Directory:</H3>"
try:
- pwd = os.getcwd()
+ pwd = os.getcwd()
except os.error, msg:
- print "os.error:", escape(str(msg))
+ print "os.error:", escape(str(msg))
else:
- print escape(pwd)
+ print escape(pwd)
print
def print_arguments():
def escape(s, quote=None):
"""Replace special characters '&', '<' and '>' by SGML entities."""
- s = string.replace(s, "&", "&") # Must be done first!
+ s = string.replace(s, "&", "&") # Must be done first!
s = string.replace(s, "<", "<")
s = string.replace(s, ">", ">",)
if quote:
- s = string.replace(s, '"', """)
+ s = string.replace(s, '"', """)
return s
code = code1 = code2 = None
try:
- code = compile(source, filename, symbol)
+ code = compile(source, filename, symbol)
except SyntaxError, err:
- pass
+ pass
try:
- code1 = compile(source + "\n", filename, symbol)
+ code1 = compile(source + "\n", filename, symbol)
except SyntaxError, err1:
- pass
+ pass
try:
- code2 = compile(source + "\n\n", filename, symbol)
+ code2 = compile(source + "\n\n", filename, symbol)
except SyntaxError, err2:
- pass
+ pass
if code:
- return code
+ return code
try:
- e1 = err1.__dict__
+ e1 = err1.__dict__
except AttributeError:
- e1 = err1
+ e1 = err1
try:
- e2 = err2.__dict__
+ e2 = err2.__dict__
except AttributeError:
- e2 = err2
+ e2 = err2
if not code1 and e1 == e2:
- raise SyntaxError, err1
+ raise SyntaxError, err1
def interact(banner=None, readfunc=raw_input, local=None):
sys.ps1 = '>>> '
sys.ps2 = '... '
if banner:
- print banner
+ print banner
else:
- print "Python Interactive Console", sys.version
- print sys.copyright
+ print "Python Interactive Console", sys.version
+ print sys.copyright
buf = []
while 1:
- if buf: prompt = sys.ps2
- else: prompt = sys.ps1
- try: line = readfunc(prompt)
- except KeyboardInterrupt:
- print "\nKeyboardInterrupt"
- buf = []
- continue
- except EOFError: break
- buf.append(line)
- try: x = compile_command(string.join(buf, "\n"))
- except SyntaxError:
- traceback.print_exc(0)
- buf = []
- continue
- if x == None: continue
- else:
- try: exec x in local
- except:
- exc_type, exc_value, exc_traceback = \
- sys.exc_type, sys.exc_value, \
- sys.exc_traceback
- l = len(traceback.extract_tb(sys.exc_traceback))
- try: 1/0
- except:
- m = len(traceback.extract_tb(
- sys.exc_traceback))
- traceback.print_exception(exc_type,
- exc_value, exc_traceback, l-m)
- buf = []
-
+ if buf: prompt = sys.ps2
+ else: prompt = sys.ps1
+ try: line = readfunc(prompt)
+ except KeyboardInterrupt:
+ print "\nKeyboardInterrupt"
+ buf = []
+ continue
+ except EOFError: break
+ buf.append(line)
+ try: x = compile_command(string.join(buf, "\n"))
+ except SyntaxError:
+ traceback.print_exc(0)
+ buf = []
+ continue
+ if x == None: continue
+ else:
+ try: exec x in local
+ except:
+ exc_type, exc_value, exc_traceback = \
+ sys.exc_type, sys.exc_value, \
+ sys.exc_traceback
+ l = len(traceback.extract_tb(sys.exc_traceback))
+ try: 1/0
+ except:
+ m = len(traceback.extract_tb(
+ sys.exc_traceback))
+ traceback.print_exception(exc_type,
+ exc_value, exc_traceback, l-m)
+ buf = []
+
if __name__ == '__main__':
interact()
#
def mkarg(x):
if '\'' not in x:
- return ' \'' + x + '\''
+ return ' \'' + x + '\''
s = ' "'
for c in x:
- if c in '\\$"`':
- s = s + '\\'
- s = s + c
+ if c in '\\$"`':
+ s = s + '\\'
+ s = s + c
s = s + '"'
return s
"""
print 'Listing', dir, '...'
try:
- names = os.listdir(dir)
+ names = os.listdir(dir)
except os.error:
- print "Can't list", dir
- names = []
+ print "Can't list", dir
+ names = []
names.sort()
for name in names:
- fullname = os.path.join(dir, name)
- if ddir:
- dfile = os.path.join(ddir, name)
- else:
- dfile = None
- if os.path.isfile(fullname):
- head, tail = name[:-3], name[-3:]
- if tail == '.py':
- print 'Compiling', fullname, '...'
- try:
- py_compile.compile(fullname, None, dfile)
- except KeyboardInterrupt:
- raise KeyboardInterrupt
- except:
- if type(sys.exc_type) == type(''):
- exc_type_name = sys.exc_type
- else: exc_type_name = sys.exc_type.__name__
- print 'Sorry:', exc_type_name + ':',
- print sys.exc_value
- elif maxlevels > 0 and \
- name != os.curdir and name != os.pardir and \
- os.path.isdir(fullname) and \
- not os.path.islink(fullname):
- compile_dir(fullname, maxlevels - 1, dfile)
+ fullname = os.path.join(dir, name)
+ if ddir:
+ dfile = os.path.join(ddir, name)
+ else:
+ dfile = None
+ if os.path.isfile(fullname):
+ head, tail = name[:-3], name[-3:]
+ if tail == '.py':
+ print 'Compiling', fullname, '...'
+ try:
+ py_compile.compile(fullname, None, dfile)
+ except KeyboardInterrupt:
+ raise KeyboardInterrupt
+ except:
+ if type(sys.exc_type) == type(''):
+ exc_type_name = sys.exc_type
+ else: exc_type_name = sys.exc_type.__name__
+ print 'Sorry:', exc_type_name + ':',
+ print sys.exc_value
+ elif maxlevels > 0 and \
+ name != os.curdir and name != os.pardir and \
+ os.path.isdir(fullname) and \
+ not os.path.islink(fullname):
+ compile_dir(fullname, maxlevels - 1, dfile)
def compile_path(skip_curdir=1, maxlevels=0):
"""Byte-compile all module on sys.path.
"""
for dir in sys.path:
- if (not dir or dir == os.curdir) and skip_curdir:
- print 'Skipping current directory'
- else:
- compile_dir(dir, maxlevels)
+ if (not dir or dir == os.curdir) and skip_curdir:
+ print 'Skipping current directory'
+ else:
+ compile_dir(dir, maxlevels)
def main():
"""Script main program."""
import getopt
try:
- opts, args = getopt.getopt(sys.argv[1:], 'ld:')
+ opts, args = getopt.getopt(sys.argv[1:], 'ld:')
except getopt.error, msg:
- print msg
- print "usage: compileall [-l] [-d destdir] [directory ...]"
- print "-l: don't recurse down"
- print "-d destdir: purported directory name for error messages"
- print "if no arguments, -l sys.path is assumed"
- sys.exit(2)
+ print msg
+ print "usage: compileall [-l] [-d destdir] [directory ...]"
+ print "-l: don't recurse down"
+ print "-d destdir: purported directory name for error messages"
+ print "if no arguments, -l sys.path is assumed"
+ sys.exit(2)
maxlevels = 10
ddir = None
for o, a in opts:
- if o == '-l': maxlevels = 0
- if o == '-d': ddir = a
+ if o == '-l': maxlevels = 0
+ if o == '-d': ddir = a
if ddir:
- if len(args) != 1:
- print "-d destdir require exactly one directory argument"
- sys.exit(2)
+ if len(args) != 1:
+ print "-d destdir require exactly one directory argument"
+ sys.exit(2)
try:
- if args:
- for dir in args:
- compile_dir(dir, maxlevels, ddir)
- else:
- compile_path()
+ if args:
+ for dir in args:
+ compile_dir(dir, maxlevels, ddir)
+ else:
+ compile_path()
except KeyboardInterrupt:
- print "\n[interrupt]"
+ print "\n[interrupt]"
if __name__ == '__main__':
main()
class Exception:
def __init__(self, *args):
- self.args = args
+ self.args = args
def __str__(self):
if not self.args:
return ''
- elif len(self.args) == 1:
- return str(self.args[0])
- else:
- return str(self.args)
+ elif len(self.args) == 1:
+ return str(self.args[0])
+ else:
+ return str(self.args)
def __getitem__(self, i):
- return self.args[i]
+ return self.args[i]
class StandardError(Exception):
pass
filename = lineno = offset = text = None
msg = ""
def __init__(self, *args):
- self.args = args
- if len(self.args) >= 1:
- self.msg = self.args[0]
- if len(self.args) == 2:
- info = self.args[1]
- try:
- self.filename, self.lineno, self.offset, self.text = info
- except:
- pass
+ self.args = args
+ if len(self.args) >= 1:
+ self.msg = self.args[0]
+ if len(self.args) == 2:
+ info = self.args[1]
+ try:
+ self.filename, self.lineno, self.offset, self.text = info
+ except:
+ pass
def __str__(self):
return str(self.msg)
class IOError(StandardError):
def __init__(self, *args):
- self.args = args
+ self.args = args
self.errno = None
self.strerror = None
if len(args) == 2:
class SystemExit(Exception):
def __init__(self, *args):
- self.args = args
+ self.args = args
if len(args) == 0:
self.code = None
elif len(args) == 1:
def input(files=(), inplace=0, backup=""):
global _state
if _state and _state._file:
- raise RuntimeError, "input() already active"
+ raise RuntimeError, "input() already active"
_state = FileInput(files, inplace, backup)
return _state
state = _state
_state = None
if state:
- state.close()
+ state.close()
def nextfile():
if not _state:
- raise RuntimeError, "no active input()"
+ raise RuntimeError, "no active input()"
return _state.nextfile()
def filename():
if not _state:
- raise RuntimeError, "no active input()"
+ raise RuntimeError, "no active input()"
return _state.filename()
def lineno():
if not _state:
- raise RuntimeError, "no active input()"
+ raise RuntimeError, "no active input()"
return _state.lineno()
def filelineno():
if not _state:
- raise RuntimeError, "no active input()"
+ raise RuntimeError, "no active input()"
return _state.filelineno()
def isfirstline():
if not _state:
- raise RuntimeError, "no active input()"
+ raise RuntimeError, "no active input()"
return _state.isfirstline()
def isstdin():
if not _state:
- raise RuntimeError, "no active input()"
+ raise RuntimeError, "no active input()"
return _state.isstdin()
class FileInput:
def __init__(self, files=(), inplace=0, backup=""):
- if type(files) == type(''):
- files = (files,)
- else:
- files = tuple(files)
- if not files:
- files = tuple(sys.argv[1:])
- if not files:
- files = ('-',)
- self._files = files
- self._inplace = inplace
- self._backup = backup
- self._savestdout = None
- self._output = None
- self._filename = None
- self._lineno = 0
- self._filelineno = 0
- self._file = None
- self._isstdin = 0
+ if type(files) == type(''):
+ files = (files,)
+ else:
+ files = tuple(files)
+ if not files:
+ files = tuple(sys.argv[1:])
+ if not files:
+ files = ('-',)
+ self._files = files
+ self._inplace = inplace
+ self._backup = backup
+ self._savestdout = None
+ self._output = None
+ self._filename = None
+ self._lineno = 0
+ self._filelineno = 0
+ self._file = None
+ self._isstdin = 0
def __del__(self):
- self.close()
+ self.close()
def close(self):
- self.nextfile()
- self._files = ()
+ self.nextfile()
+ self._files = ()
def __getitem__(self, i):
- if i != self._lineno:
- raise RuntimeError, "accessing lines out of order"
- line = self.readline()
- if not line:
- raise IndexError, "end of input reached"
- return line
+ if i != self._lineno:
+ raise RuntimeError, "accessing lines out of order"
+ line = self.readline()
+ if not line:
+ raise IndexError, "end of input reached"
+ return line
def nextfile(self):
- savestdout = self._savestdout
- self._savestdout = 0
- if savestdout:
- sys.stdout = savestdout
+ savestdout = self._savestdout
+ self._savestdout = 0
+ if savestdout:
+ sys.stdout = savestdout
- output = self._output
- self._output = 0
- if output:
- output.close()
+ output = self._output
+ self._output = 0
+ if output:
+ output.close()
- file = self._file
- self._file = 0
- if file and not self._isstdin:
- file.close()
+ file = self._file
+ self._file = 0
+ if file and not self._isstdin:
+ file.close()
- backupfilename = self._backupfilename
- self._backupfilename = 0
- if backupfilename and not self._backup:
- try: os.unlink(backupfilename)
- except: pass
+ backupfilename = self._backupfilename
+ self._backupfilename = 0
+ if backupfilename and not self._backup:
+ try: os.unlink(backupfilename)
+ except: pass
- self._isstdin = 0
+ self._isstdin = 0
def readline(self):
- if not self._file:
- if not self._files:
- return ""
- self._filename = self._files[0]
- self._files = self._files[1:]
- self._filelineno = 0
- self._file = None
- self._isstdin = 0
- self._backupfilename = 0
- if self._filename == '-':
- self._filename = '<stdin>'
- self._file = sys.stdin
- self._isstdin = 1
- else:
- if self._inplace:
- self._backupfilename = (
- self._filename + (self._backup or ".bak"))
- try: os.unlink(self._backupfilename)
- except os.error: pass
- # The next three lines may raise IOError
- os.rename(self._filename, self._backupfilename)
- self._file = open(self._backupfilename, "r")
- self._output = open(self._filename, "w")
- self._savestdout = sys.stdout
- sys.stdout = self._output
- else:
- # This may raise IOError
- self._file = open(self._filename, "r")
- line = self._file.readline()
- if line:
- self._lineno = self._lineno + 1
- self._filelineno = self._filelineno + 1
- return line
- self.nextfile()
- # Recursive call
- return self.readline()
+ if not self._file:
+ if not self._files:
+ return ""
+ self._filename = self._files[0]
+ self._files = self._files[1:]
+ self._filelineno = 0
+ self._file = None
+ self._isstdin = 0
+ self._backupfilename = 0
+ if self._filename == '-':
+ self._filename = '<stdin>'
+ self._file = sys.stdin
+ self._isstdin = 1
+ else:
+ if self._inplace:
+ self._backupfilename = (
+ self._filename + (self._backup or ".bak"))
+ try: os.unlink(self._backupfilename)
+ except os.error: pass
+ # The next three lines may raise IOError
+ os.rename(self._filename, self._backupfilename)
+ self._file = open(self._backupfilename, "r")
+ self._output = open(self._filename, "w")
+ self._savestdout = sys.stdout
+ sys.stdout = self._output
+ else:
+ # This may raise IOError
+ self._file = open(self._filename, "r")
+ line = self._file.readline()
+ if line:
+ self._lineno = self._lineno + 1
+ self._filelineno = self._filelineno + 1
+ return line
+ self.nextfile()
+ # Recursive call
+ return self.readline()
def filename(self):
- return self._filename
+ return self._filename
def lineno(self):
- return self._lineno
+ return self._lineno
def filelineno(self):
- return self._filelineno
+ return self._filelineno
def isfirstline(self):
- return self._filelineno == 1
+ return self._filelineno == 1
def isstdin(self):
- return self._isstdin
+ return self._isstdin
def _test():
import getopt
backup = 0
opts, args = getopt.getopt(sys.argv[1:], "ib:")
for o, a in opts:
- if o == '-i': inplace = 1
- if o == '-b': backup = a
+ if o == '-i': inplace = 1
+ if o == '-b': backup = a
for line in input(args, inplace=inplace, backup=backup):
- if line[-1:] == '\n': line = line[:-1]
- if line[-1:] == '\r': line = line[:-1]
- print "%d: %s[%d]%s %s" % (lineno(), filename(), filelineno(),
- isfirstline() and "*" or "", line)
+ if line[-1:] == '\n': line = line[:-1]
+ if line[-1:] == '\r': line = line[:-1]
+ print "%d: %s[%d]%s %s" % (lineno(), filename(), filelineno(),
+ isfirstline() and "*" or "", line)
print "%d: %s[%d]" % (lineno(), filename(), filelineno())
if __name__ == '__main__':
class NullFormatter:
def __init__(self, writer=None):
- if not writer:
- writer = NullWriter()
- self.writer = writer
+ if not writer:
+ writer = NullWriter()
+ self.writer = writer
def end_paragraph(self, blankline): pass
def add_line_break(self): pass
def add_hor_rule(self, *args, **kw): pass
# in all circumstances.
def __init__(self, writer):
- self.writer = writer # Output device
- self.align = None # Current alignment
- self.align_stack = [] # Alignment stack
- self.font_stack = [] # Font state
- self.margin_stack = [] # Margin state
- self.spacing = None # Vertical spacing state
- self.style_stack = [] # Other state, e.g. color
- self.nospace = 1 # Should leading space be suppressed
- self.softspace = 0 # Should a space be inserted
- self.para_end = 1 # Just ended a paragraph
- self.parskip = 0 # Skipped space between paragraphs?
- self.hard_break = 1 # Have a hard break
- self.have_label = 0
+ self.writer = writer # Output device
+ self.align = None # Current alignment
+ self.align_stack = [] # Alignment stack
+ self.font_stack = [] # Font state
+ self.margin_stack = [] # Margin state
+ self.spacing = None # Vertical spacing state
+ self.style_stack = [] # Other state, e.g. color
+ self.nospace = 1 # Should leading space be suppressed
+ self.softspace = 0 # Should a space be inserted
+ self.para_end = 1 # Just ended a paragraph
+ self.parskip = 0 # Skipped space between paragraphs?
+ self.hard_break = 1 # Have a hard break
+ self.have_label = 0
def end_paragraph(self, blankline):
- if not self.hard_break:
- self.writer.send_line_break()
- self.have_label = 0
- if self.parskip < blankline and not self.have_label:
- self.writer.send_paragraph(blankline - self.parskip)
- self.parskip = blankline
- self.have_label = 0
- self.hard_break = self.nospace = self.para_end = 1
- self.softspace = 0
+ if not self.hard_break:
+ self.writer.send_line_break()
+ self.have_label = 0
+ if self.parskip < blankline and not self.have_label:
+ self.writer.send_paragraph(blankline - self.parskip)
+ self.parskip = blankline
+ self.have_label = 0
+ self.hard_break = self.nospace = self.para_end = 1
+ self.softspace = 0
def add_line_break(self):
- if not (self.hard_break or self.para_end):
- self.writer.send_line_break()
- self.have_label = self.parskip = 0
- self.hard_break = self.nospace = 1
- self.softspace = 0
+ if not (self.hard_break or self.para_end):
+ self.writer.send_line_break()
+ self.have_label = self.parskip = 0
+ self.hard_break = self.nospace = 1
+ self.softspace = 0
def add_hor_rule(self, *args, **kw):
- if not self.hard_break:
- self.writer.send_line_break()
- apply(self.writer.send_hor_rule, args, kw)
- self.hard_break = self.nospace = 1
- self.have_label = self.para_end = self.softspace = self.parskip = 0
+ if not self.hard_break:
+ self.writer.send_line_break()
+ apply(self.writer.send_hor_rule, args, kw)
+ self.hard_break = self.nospace = 1
+ self.have_label = self.para_end = self.softspace = self.parskip = 0
def add_label_data(self, format, counter, blankline = None):
- if self.have_label or not self.hard_break:
- self.writer.send_line_break()
- if not self.para_end:
- self.writer.send_paragraph((blankline and 1) or 0)
- if type(format) is StringType:
- self.writer.send_label_data(self.format_counter(format, counter))
- else:
- self.writer.send_label_data(format)
- self.nospace = self.have_label = self.hard_break = self.para_end = 1
- self.softspace = self.parskip = 0
+ if self.have_label or not self.hard_break:
+ self.writer.send_line_break()
+ if not self.para_end:
+ self.writer.send_paragraph((blankline and 1) or 0)
+ if type(format) is StringType:
+ self.writer.send_label_data(self.format_counter(format, counter))
+ else:
+ self.writer.send_label_data(format)
+ self.nospace = self.have_label = self.hard_break = self.para_end = 1
+ self.softspace = self.parskip = 0
def format_counter(self, format, counter):
label = ''
for c in format:
try:
if c == '1':
- label = label + ('%d' % counter)
+ label = label + ('%d' % counter)
elif c in 'aA':
- if counter > 0:
- label = label + self.format_letter(c, counter)
+ if counter > 0:
+ label = label + self.format_letter(c, counter)
elif c in 'iI':
- if counter > 0:
- label = label + self.format_roman(c, counter)
- else:
- label = label + c
+ if counter > 0:
+ label = label + self.format_roman(c, counter)
+ else:
+ label = label + c
except:
label = label + c
return label
def format_letter(self, case, counter):
- label = ''
- while counter > 0:
- counter, x = divmod(counter-1, 26)
- s = chr(ord(case) + x)
- label = s + label
- return label
+ label = ''
+ while counter > 0:
+ counter, x = divmod(counter-1, 26)
+ s = chr(ord(case) + x)
+ label = s + label
+ return label
def format_roman(self, case, counter):
ones = ['i', 'x', 'c', 'm']
fives = ['v', 'l', 'd']
label, index = '', 0
- # This will die of IndexError when counter is too big
+ # This will die of IndexError when counter is too big
while counter > 0:
counter, x = divmod(counter, 10)
if x == 9:
else:
s = ''
s = s + ones[index]*x
- label = s + label
+ label = s + label
index = index + 1
if case == 'I':
- return string.upper(label)
+ return string.upper(label)
return label
def add_flowing_data(self, data,
- # These are only here to load them into locals:
- whitespace = string.whitespace,
- join = string.join, split = string.split):
- if not data: return
- # The following looks a bit convoluted but is a great improvement over
- # data = regsub.gsub('[' + string.whitespace + ']+', ' ', data)
- prespace = data[:1] in whitespace
- postspace = data[-1:] in whitespace
- data = join(split(data))
- if self.nospace and not data:
- return
- elif prespace or self.softspace:
- if not data:
- if not self.nospace:
- self.softspace = 1
- self.parskip = 0
- return
- if not self.nospace:
- data = ' ' + data
- self.hard_break = self.nospace = self.para_end = \
- self.parskip = self.have_label = 0
- self.softspace = postspace
- self.writer.send_flowing_data(data)
+ # These are only here to load them into locals:
+ whitespace = string.whitespace,
+ join = string.join, split = string.split):
+ if not data: return
+ # The following looks a bit convoluted but is a great improvement over
+ # data = regsub.gsub('[' + string.whitespace + ']+', ' ', data)
+ prespace = data[:1] in whitespace
+ postspace = data[-1:] in whitespace
+ data = join(split(data))
+ if self.nospace and not data:
+ return
+ elif prespace or self.softspace:
+ if not data:
+ if not self.nospace:
+ self.softspace = 1
+ self.parskip = 0
+ return
+ if not self.nospace:
+ data = ' ' + data
+ self.hard_break = self.nospace = self.para_end = \
+ self.parskip = self.have_label = 0
+ self.softspace = postspace
+ self.writer.send_flowing_data(data)
def add_literal_data(self, data):
- if not data: return
- if self.softspace:
- self.writer.send_flowing_data(" ")
- self.hard_break = data[-1:] == '\n'
- self.nospace = self.para_end = self.softspace = \
- self.parskip = self.have_label = 0
- self.writer.send_literal_data(data)
+ if not data: return
+ if self.softspace:
+ self.writer.send_flowing_data(" ")
+ self.hard_break = data[-1:] == '\n'
+ self.nospace = self.para_end = self.softspace = \
+ self.parskip = self.have_label = 0
+ self.writer.send_literal_data(data)
def flush_softspace(self):
- if self.softspace:
- self.hard_break = self.para_end = self.parskip = \
- self.have_label = self.softspace = 0
- self.nospace = 1
- self.writer.send_flowing_data(' ')
+ if self.softspace:
+ self.hard_break = self.para_end = self.parskip = \
+ self.have_label = self.softspace = 0
+ self.nospace = 1
+ self.writer.send_flowing_data(' ')
def push_alignment(self, align):
- if align and align != self.align:
- self.writer.new_alignment(align)
- self.align = align
- self.align_stack.append(align)
- else:
- self.align_stack.append(self.align)
+ if align and align != self.align:
+ self.writer.new_alignment(align)
+ self.align = align
+ self.align_stack.append(align)
+ else:
+ self.align_stack.append(self.align)
def pop_alignment(self):
- if self.align_stack:
- del self.align_stack[-1]
- if self.align_stack:
- self.align = align = self.align_stack[-1]
- self.writer.new_alignment(align)
- else:
- self.align = None
- self.writer.new_alignment(None)
+ if self.align_stack:
+ del self.align_stack[-1]
+ if self.align_stack:
+ self.align = align = self.align_stack[-1]
+ self.writer.new_alignment(align)
+ else:
+ self.align = None
+ self.writer.new_alignment(None)
def push_font(self, (size, i, b, tt)):
- if self.softspace:
- self.hard_break = self.para_end = self.softspace = 0
- self.nospace = 1
- self.writer.send_flowing_data(' ')
- if self.font_stack:
- csize, ci, cb, ctt = self.font_stack[-1]
- if size is AS_IS: size = csize
- if i is AS_IS: i = ci
- if b is AS_IS: b = cb
- if tt is AS_IS: tt = ctt
- font = (size, i, b, tt)
- self.font_stack.append(font)
- self.writer.new_font(font)
+ if self.softspace:
+ self.hard_break = self.para_end = self.softspace = 0
+ self.nospace = 1
+ self.writer.send_flowing_data(' ')
+ if self.font_stack:
+ csize, ci, cb, ctt = self.font_stack[-1]
+ if size is AS_IS: size = csize
+ if i is AS_IS: i = ci
+ if b is AS_IS: b = cb
+ if tt is AS_IS: tt = ctt
+ font = (size, i, b, tt)
+ self.font_stack.append(font)
+ self.writer.new_font(font)
def pop_font(self):
- if self.font_stack:
- del self.font_stack[-1]
- if self.font_stack:
- font = self.font_stack[-1]
- else:
- font = None
- self.writer.new_font(font)
+ if self.font_stack:
+ del self.font_stack[-1]
+ if self.font_stack:
+ font = self.font_stack[-1]
+ else:
+ font = None
+ self.writer.new_font(font)
def push_margin(self, margin):
- self.margin_stack.append(margin)
- fstack = filter(None, self.margin_stack)
- if not margin and fstack:
- margin = fstack[-1]
- self.writer.new_margin(margin, len(fstack))
+ self.margin_stack.append(margin)
+ fstack = filter(None, self.margin_stack)
+ if not margin and fstack:
+ margin = fstack[-1]
+ self.writer.new_margin(margin, len(fstack))
def pop_margin(self):
- if self.margin_stack:
- del self.margin_stack[-1]
- fstack = filter(None, self.margin_stack)
- if fstack:
- margin = fstack[-1]
- else:
- margin = None
- self.writer.new_margin(margin, len(fstack))
+ if self.margin_stack:
+ del self.margin_stack[-1]
+ fstack = filter(None, self.margin_stack)
+ if fstack:
+ margin = fstack[-1]
+ else:
+ margin = None
+ self.writer.new_margin(margin, len(fstack))
def set_spacing(self, spacing):
- self.spacing = spacing
- self.writer.new_spacing(spacing)
+ self.spacing = spacing
+ self.writer.new_spacing(spacing)
def push_style(self, *styles):
- if self.softspace:
- self.hard_break = self.para_end = self.softspace = 0
- self.nospace = 1
- self.writer.send_flowing_data(' ')
- for style in styles:
- self.style_stack.append(style)
- self.writer.new_styles(tuple(self.style_stack))
+ if self.softspace:
+ self.hard_break = self.para_end = self.softspace = 0
+ self.nospace = 1
+ self.writer.send_flowing_data(' ')
+ for style in styles:
+ self.style_stack.append(style)
+ self.writer.new_styles(tuple(self.style_stack))
def pop_style(self, n=1):
- del self.style_stack[-n:]
- self.writer.new_styles(tuple(self.style_stack))
+ del self.style_stack[-n:]
+ self.writer.new_styles(tuple(self.style_stack))
def assert_line_data(self, flag=1):
- self.nospace = self.hard_break = not flag
- self.para_end = self.parskip = self.have_label = 0
+ self.nospace = self.hard_break = not flag
+ self.para_end = self.parskip = self.have_label = 0
class NullWriter:
class AbstractWriter(NullWriter):
def __init__(self):
- pass
+ pass
def new_alignment(self, align):
- print "new_alignment(%s)" % `align`
+ print "new_alignment(%s)" % `align`
def new_font(self, font):
- print "new_font(%s)" % `font`
+ print "new_font(%s)" % `font`
def new_margin(self, margin, level):
- print "new_margin(%s, %d)" % (`margin`, level)
+ print "new_margin(%s, %d)" % (`margin`, level)
def new_spacing(self, spacing):
- print "new_spacing(%s)" % `spacing`
+ print "new_spacing(%s)" % `spacing`
def new_styles(self, styles):
- print "new_styles(%s)" % `styles`
+ print "new_styles(%s)" % `styles`
def send_paragraph(self, blankline):
- print "send_paragraph(%s)" % `blankline`
+ print "send_paragraph(%s)" % `blankline`
def send_line_break(self):
- print "send_line_break()"
+ print "send_line_break()"
def send_hor_rule(self, *args, **kw):
- print "send_hor_rule()"
+ print "send_hor_rule()"
def send_label_data(self, data):
- print "send_label_data(%s)" % `data`
+ print "send_label_data(%s)" % `data`
def send_flowing_data(self, data):
- print "send_flowing_data(%s)" % `data`
+ print "send_flowing_data(%s)" % `data`
def send_literal_data(self, data):
- print "send_literal_data(%s)" % `data`
+ print "send_literal_data(%s)" % `data`
class DumbWriter(NullWriter):
def __init__(self, file=None, maxcol=72):
- self.file = file or sys.stdout
- self.maxcol = maxcol
- NullWriter.__init__(self)
- self.reset()
+ self.file = file or sys.stdout
+ self.maxcol = maxcol
+ NullWriter.__init__(self)
+ self.reset()
def reset(self):
- self.col = 0
- self.atbreak = 0
+ self.col = 0
+ self.atbreak = 0
def send_paragraph(self, blankline):
- self.file.write('\n' + '\n'*blankline)
- self.col = 0
- self.atbreak = 0
+ self.file.write('\n' + '\n'*blankline)
+ self.col = 0
+ self.atbreak = 0
def send_line_break(self):
- self.file.write('\n')
- self.col = 0
- self.atbreak = 0
+ self.file.write('\n')
+ self.col = 0
+ self.atbreak = 0
def send_hor_rule(self, *args, **kw):
- self.file.write('\n')
- self.file.write('-'*self.maxcol)
- self.file.write('\n')
- self.col = 0
- self.atbreak = 0
+ self.file.write('\n')
+ self.file.write('-'*self.maxcol)
+ self.file.write('\n')
+ self.col = 0
+ self.atbreak = 0
def send_literal_data(self, data):
- self.file.write(data)
- i = string.rfind(data, '\n')
- if i >= 0:
- self.col = 0
- data = data[i+1:]
- data = string.expandtabs(data)
- self.col = self.col + len(data)
- self.atbreak = 0
+ self.file.write(data)
+ i = string.rfind(data, '\n')
+ if i >= 0:
+ self.col = 0
+ data = data[i+1:]
+ data = string.expandtabs(data)
+ self.col = self.col + len(data)
+ self.atbreak = 0
def send_flowing_data(self, data):
- if not data: return
- atbreak = self.atbreak or data[0] in string.whitespace
- col = self.col
- maxcol = self.maxcol
- write = self.file.write
- for word in string.split(data):
- if atbreak:
- if col + len(word) >= maxcol:
- write('\n')
- col = 0
- else:
- write(' ')
- col = col + 1
- write(word)
- col = col + len(word)
- atbreak = 1
- self.col = col
- self.atbreak = data[-1] in string.whitespace
+ if not data: return
+ atbreak = self.atbreak or data[0] in string.whitespace
+ col = self.col
+ maxcol = self.maxcol
+ write = self.file.write
+ for word in string.split(data):
+ if atbreak:
+ if col + len(word) >= maxcol:
+ write('\n')
+ col = 0
+ else:
+ write(' ')
+ col = col + 1
+ write(word)
+ col = col + len(word)
+ atbreak = 1
+ self.col = col
+ self.atbreak = data[-1] in string.whitespace
def test(file = None):
w = DumbWriter()
f = AbstractFormatter(w)
if file:
- fp = open(file)
+ fp = open(file)
elif sys.argv[1:]:
- fp = open(sys.argv[1])
+ fp = open(sys.argv[1])
else:
- fp = sys.stdin
+ fp = sys.stdin
while 1:
- line = fp.readline()
- if not line:
- break
- if line == '\n':
- f.end_paragraph(1)
- else:
- f.add_flowing_data(line)
+ line = fp.readline()
+ if not line:
+ break
+ if line == '\n':
+ f.end_paragraph(1)
+ else:
+ f.add_flowing_data(line)
f.end_paragraph(0)
# detects an error.
# It returns two values:
-# (1) a list of pairs (option, option_argument) giving the options in
-# the order in which they were specified. (I'd use a dictionary
-# but applications may depend on option order or multiple
-# occurrences.) Boolean options have '' as option_argument.
-# (2) the list of remaining arguments (may be empty).
+# (1) a list of pairs (option, option_argument) giving the options in
+# the order in which they were specified. (I'd use a dictionary
+# but applications may depend on option order or multiple
+# occurrences.) Boolean options have '' as option_argument.
+# (2) the list of remaining arguments (may be empty).
import string
longopts = longopts[:]
longopts.sort()
while args and args[0][:1] == '-' and args[0] != '-':
- if args[0] == '--':
- args = args[1:]
- break
- if args[0][:2] == '--':
- list, args = do_longs(list, args[0][2:], longopts, args[1:])
- else:
- list, args = do_shorts(list, args[0][1:], shortopts, args[1:])
+ if args[0] == '--':
+ args = args[1:]
+ break
+ if args[0][:2] == '--':
+ list, args = do_longs(list, args[0][2:], longopts, args[1:])
+ else:
+ list, args = do_shorts(list, args[0][1:], shortopts, args[1:])
return list, args
def do_longs(list, opt, longopts, args):
try:
- i = string.index(opt, '=')
- opt, optarg = opt[:i], opt[i+1:]
+ i = string.index(opt, '=')
+ opt, optarg = opt[:i], opt[i+1:]
except ValueError:
- optarg = None
+ optarg = None
has_arg, opt = long_has_args(opt, longopts)
if has_arg:
- if optarg is None:
- if not args:
- raise error, 'option --%s requires argument' % opt
- optarg, args = args[0], args[1:]
+ if optarg is None:
+ if not args:
+ raise error, 'option --%s requires argument' % opt
+ optarg, args = args[0], args[1:]
elif optarg:
- raise error, 'option --%s must not have an argument' % opt
+ raise error, 'option --%s must not have an argument' % opt
list.append(('--' + opt, optarg or ''))
return list, args
def long_has_args(opt, longopts):
optlen = len(opt)
for i in range(len(longopts)):
- x, y = longopts[i][:optlen], longopts[i][optlen:]
- if opt != x:
- continue
- if y != '' and y != '=' and i+1 < len(longopts):
- if opt == longopts[i+1][:optlen]:
- raise error, 'option --%s not a unique prefix' % opt
- if longopts[i][-1:] in ('=', ):
- return 1, longopts[i][:-1]
- return 0, longopts[i]
+ x, y = longopts[i][:optlen], longopts[i][optlen:]
+ if opt != x:
+ continue
+ if y != '' and y != '=' and i+1 < len(longopts):
+ if opt == longopts[i+1][:optlen]:
+ raise error, 'option --%s not a unique prefix' % opt
+ if longopts[i][-1:] in ('=', ):
+ return 1, longopts[i][:-1]
+ return 0, longopts[i]
raise error, 'option --' + opt + ' not recognized'
def do_shorts(list, optstring, shortopts, args):
while optstring != '':
- opt, optstring = optstring[0], optstring[1:]
- if short_has_arg(opt, shortopts):
- if optstring == '':
- if not args:
- raise error, 'option -%s requires argument' % opt
- optstring, args = args[0], args[1:]
- optarg, optstring = optstring, ''
- else:
- optarg = ''
- list.append(('-' + opt, optarg))
+ opt, optstring = optstring[0], optstring[1:]
+ if short_has_arg(opt, shortopts):
+ if optstring == '':
+ if not args:
+ raise error, 'option -%s requires argument' % opt
+ optstring, args = args[0], args[1:]
+ optarg, optstring = optstring, ''
+ else:
+ optarg = ''
+ list.append(('-' + opt, optarg))
return list, args
def short_has_arg(opt, shortopts):
for i in range(len(shortopts)):
- if opt == shortopts[i] != ':':
- return shortopts[i+1:i+2] == ':'
+ if opt == shortopts[i] != ':':
+ return shortopts[i+1:i+2] == ':'
raise error, 'option -%s not recognized' % opt
if __name__ == '__main__':
myfileobj = None
def __init__(self, filename=None, mode=None,
- compresslevel=9, fileobj=None):
- if fileobj is None:
- fileobj = self.myfileobj = __builtin__.open(filename, mode or 'r')
+ compresslevel=9, fileobj=None):
+ if fileobj is None:
+ fileobj = self.myfileobj = __builtin__.open(filename, mode or 'r')
if filename is None:
- if hasattr(fileobj, 'name'): filename = fileobj.name
- else: filename = ''
+ if hasattr(fileobj, 'name'): filename = fileobj.name
+ else: filename = ''
if mode is None:
- if hasattr(fileobj, 'mode'): mode = fileobj.mode
- else: mode = 'r'
-
- if mode[0:1] == 'r':
- self.mode = READ
- self._init_read()
- self.filename = filename
- self.decompress = zlib.decompressobj(-zlib.MAX_WBITS)
-
- elif mode[0:1] == 'w':
- self.mode = WRITE
- self._init_write(filename)
- self.compress = zlib.compressobj(compresslevel,
- zlib.DEFLATED,
- -zlib.MAX_WBITS,
- zlib.DEF_MEM_LEVEL,
- 0)
- else:
- raise ValueError, "Mode " + mode + " not supported"
-
- self.fileobj = fileobj
-
- if self.mode == WRITE:
- self._write_gzip_header()
- elif self.mode == READ:
- self._read_gzip_header()
+ if hasattr(fileobj, 'mode'): mode = fileobj.mode
+ else: mode = 'r'
+
+ if mode[0:1] == 'r':
+ self.mode = READ
+ self._init_read()
+ self.filename = filename
+ self.decompress = zlib.decompressobj(-zlib.MAX_WBITS)
+
+ elif mode[0:1] == 'w':
+ self.mode = WRITE
+ self._init_write(filename)
+ self.compress = zlib.compressobj(compresslevel,
+ zlib.DEFLATED,
+ -zlib.MAX_WBITS,
+ zlib.DEF_MEM_LEVEL,
+ 0)
+ else:
+ raise ValueError, "Mode " + mode + " not supported"
+
+ self.fileobj = fileobj
+
+ if self.mode == WRITE:
+ self._write_gzip_header()
+ elif self.mode == READ:
+ self._read_gzip_header()
def __repr__(self):
- s = repr(self.fileobj)
- return '<gzip ' + s[1:-1] + ' ' + hex(id(self)) + '>'
+ s = repr(self.fileobj)
+ return '<gzip ' + s[1:-1] + ' ' + hex(id(self)) + '>'
def _init_write(self, filename):
- if filename[-3:] != '.gz':
- filename = filename + '.gz'
- self.filename = filename
- self.crc = zlib.crc32("")
- self.size = 0
- self.writebuf = []
- self.bufsize = 0
+ if filename[-3:] != '.gz':
+ filename = filename + '.gz'
+ self.filename = filename
+ self.crc = zlib.crc32("")
+ self.size = 0
+ self.writebuf = []
+ self.bufsize = 0
def _write_gzip_header(self):
- self.fileobj.write('\037\213') # magic header
- self.fileobj.write('\010') # compression method
- fname = self.filename[:-3]
- flags = 0
- if fname:
- flags = FNAME
- self.fileobj.write(chr(flags))
- write32(self.fileobj, int(time.time()))
- self.fileobj.write('\002')
- self.fileobj.write('\377')
- if fname:
- self.fileobj.write(fname + '\000')
+ self.fileobj.write('\037\213') # magic header
+ self.fileobj.write('\010') # compression method
+ fname = self.filename[:-3]
+ flags = 0
+ if fname:
+ flags = FNAME
+ self.fileobj.write(chr(flags))
+ write32(self.fileobj, int(time.time()))
+ self.fileobj.write('\002')
+ self.fileobj.write('\377')
+ if fname:
+ self.fileobj.write(fname + '\000')
def _init_read(self):
- self.crc = zlib.crc32("")
- self.size = 0
- self.extrabuf = ""
- self.extrasize = 0
+ self.crc = zlib.crc32("")
+ self.size = 0
+ self.extrabuf = ""
+ self.extrasize = 0
def _read_gzip_header(self):
- magic = self.fileobj.read(2)
- if magic != '\037\213':
- raise RuntimeError, 'Not a gzipped file'
- method = ord( self.fileobj.read(1) )
- if method != 8:
- raise RuntimeError, 'Unknown compression method'
- flag = ord( self.fileobj.read(1) )
- # modtime = self.fileobj.read(4)
- # extraflag = self.fileobj.read(1)
- # os = self.fileobj.read(1)
- self.fileobj.read(6)
-
- if flag & FEXTRA:
- # Read & discard the extra field, if present
- xlen=ord(self.fileobj.read(1))
- xlen=xlen+256*ord(self.fileobj.read(1))
- self.fileobj.read(xlen)
- if flag & FNAME:
- # Read and discard a null-terminated string containing the filename
- while (1):
- s=self.fileobj.read(1)
- if not s or s=='\000': break
- if flag & FCOMMENT:
- # Read and discard a null-terminated string containing a comment
- while (1):
- s=self.fileobj.read(1)
- if not s or s=='\000': break
- if flag & FHCRC:
- self.fileobj.read(2) # Read & discard the 16-bit header CRC
+ magic = self.fileobj.read(2)
+ if magic != '\037\213':
+ raise RuntimeError, 'Not a gzipped file'
+ method = ord( self.fileobj.read(1) )
+ if method != 8:
+ raise RuntimeError, 'Unknown compression method'
+ flag = ord( self.fileobj.read(1) )
+ # modtime = self.fileobj.read(4)
+ # extraflag = self.fileobj.read(1)
+ # os = self.fileobj.read(1)
+ self.fileobj.read(6)
+
+ if flag & FEXTRA:
+ # Read & discard the extra field, if present
+ xlen=ord(self.fileobj.read(1))
+ xlen=xlen+256*ord(self.fileobj.read(1))
+ self.fileobj.read(xlen)
+ if flag & FNAME:
+ # Read and discard a null-terminated string containing the filename
+ while (1):
+ s=self.fileobj.read(1)
+ if not s or s=='\000': break
+ if flag & FCOMMENT:
+ # Read and discard a null-terminated string containing a comment
+ while (1):
+ s=self.fileobj.read(1)
+ if not s or s=='\000': break
+ if flag & FHCRC:
+ self.fileobj.read(2) # Read & discard the 16-bit header CRC
def write(self,data):
- if self.fileobj is None:
- raise ValueError, "write() on closed GzipFile object"
- if len(data) > 0:
- self.size = self.size + len(data)
- self.crc = zlib.crc32(data, self.crc)
- self.fileobj.write( self.compress.compress(data) )
+ if self.fileobj is None:
+ raise ValueError, "write() on closed GzipFile object"
+ if len(data) > 0:
+ self.size = self.size + len(data)
+ self.crc = zlib.crc32(data, self.crc)
+ self.fileobj.write( self.compress.compress(data) )
def writelines(self,lines):
- self.write(string.join(lines))
+ self.write(string.join(lines))
def read(self,size=None):
- if self.extrasize <= 0 and self.fileobj is None:
- return ''
-
- readsize = 1024
- if not size: # get the whole thing
- try:
- while 1:
- self._read(readsize)
- readsize = readsize * 2
- except EOFError:
- size = self.extrasize
- else: # just get some more of it
- try:
- while size > self.extrasize:
- self._read(readsize)
- readsize = readsize * 2
- except EOFError:
- pass
-
- chunk = self.extrabuf[:size]
- self.extrabuf = self.extrabuf[size:]
- self.extrasize = self.extrasize - size
-
- return chunk
+ if self.extrasize <= 0 and self.fileobj is None:
+ return ''
+
+ readsize = 1024
+ if not size: # get the whole thing
+ try:
+ while 1:
+ self._read(readsize)
+ readsize = readsize * 2
+ except EOFError:
+ size = self.extrasize
+ else: # just get some more of it
+ try:
+ while size > self.extrasize:
+ self._read(readsize)
+ readsize = readsize * 2
+ except EOFError:
+ pass
+
+ chunk = self.extrabuf[:size]
+ self.extrabuf = self.extrabuf[size:]
+ self.extrasize = self.extrasize - size
+
+ return chunk
def _unread(self, buf):
- self.extrabuf = buf + self.extrabuf
- self.extrasize = len(buf) + self.extrasize
+ self.extrabuf = buf + self.extrabuf
+ self.extrasize = len(buf) + self.extrasize
def _read(self, size=1024):
- try:
- buf = self.fileobj.read(size)
- except AttributeError:
- raise EOFError, "Reached EOF"
- if buf == "":
- uncompress = self.decompress.flush()
- if uncompress == "":
- self._read_eof()
- self.fileobj = None
- raise EOFError, 'Reached EOF'
- else:
- uncompress = self.decompress.decompress(buf)
- self.crc = zlib.crc32(uncompress, self.crc)
- self.extrabuf = self.extrabuf + uncompress
- self.extrasize = self.extrasize + len(uncompress)
- self.size = self.size + len(uncompress)
+ try:
+ buf = self.fileobj.read(size)
+ except AttributeError:
+ raise EOFError, "Reached EOF"
+ if buf == "":
+ uncompress = self.decompress.flush()
+ if uncompress == "":
+ self._read_eof()
+ self.fileobj = None
+ raise EOFError, 'Reached EOF'
+ else:
+ uncompress = self.decompress.decompress(buf)
+ self.crc = zlib.crc32(uncompress, self.crc)
+ self.extrabuf = self.extrabuf + uncompress
+ self.extrasize = self.extrasize + len(uncompress)
+ self.size = self.size + len(uncompress)
def _read_eof(self):
- # Andrew writes:
- ## We've read to the end of the file, so we have to rewind in order
- ## to reread the 8 bytes containing the CRC and the file size. The
- ## decompressor is smart and knows when to stop, so feeding it
- ## extra data is harmless.
- self.fileobj.seek(-8, 2)
- crc32 = read32(self.fileobj)
- isize = read32(self.fileobj)
- if crc32 != self.crc:
- self.error = "CRC check failed"
- elif isize != self.size:
- self.error = "Incorrect length of data produced"
+ # Andrew writes:
+ ## We've read to the end of the file, so we have to rewind in order
+ ## to reread the 8 bytes containing the CRC and the file size. The
+ ## decompressor is smart and knows when to stop, so feeding it
+ ## extra data is harmless.
+ self.fileobj.seek(-8, 2)
+ crc32 = read32(self.fileobj)
+ isize = read32(self.fileobj)
+ if crc32 != self.crc:
+ self.error = "CRC check failed"
+ elif isize != self.size:
+ self.error = "Incorrect length of data produced"
def close(self):
- if self.mode == WRITE:
- self.fileobj.write(self.compress.flush())
- write32(self.fileobj, self.crc)
- write32(self.fileobj, self.size)
- self.fileobj = None
- elif self.mode == READ:
- self.fileobj = None
- if self.myfileobj:
- self.myfileobj.close()
- self.myfileobj = None
+ if self.mode == WRITE:
+ self.fileobj.write(self.compress.flush())
+ write32(self.fileobj, self.crc)
+ write32(self.fileobj, self.size)
+ self.fileobj = None
+ elif self.mode == READ:
+ self.fileobj = None
+ if self.myfileobj:
+ self.myfileobj.close()
+ self.myfileobj = None
def flush(self):
- self.fileobj.flush()
+ self.fileobj.flush()
def seek(self):
- raise IOError, 'Random access not allowed in gzip files'
+ raise IOError, 'Random access not allowed in gzip files'
def tell(self):
- raise IOError, 'I won\'t tell() you for gzip files'
+ raise IOError, 'I won\'t tell() you for gzip files'
def isatty(self):
- return 0
+ return 0
def readline(self):
- bufs = []
- readsize = 100
- while 1:
- c = self.read(readsize)
- i = string.find(c, '\n')
- if i >= 0 or c == '':
- bufs.append(c[:i])
- self._unread(c[i+1:])
- return string.join(bufs, '')
- bufs.append(c)
- readsize = readsize * 2
+ bufs = []
+ readsize = 100
+ while 1:
+ c = self.read(readsize)
+ i = string.find(c, '\n')
+ if i >= 0 or c == '':
+ bufs.append(c[:i])
+ self._unread(c[i+1:])
+ return string.join(bufs, '')
+ bufs.append(c)
+ readsize = readsize * 2
def readlines(self):
- buf = self.read()
- return string.split(buf, '\n')
+ buf = self.read()
+ return string.split(buf, '\n')
def writelines(self, L):
- for line in L:
- self.write(line)
+ for line in L:
+ self.write(line)
def _test():
args = sys.argv[1:]
decompress = args and args[0] == "-d"
if decompress:
- args = args[1:]
+ args = args[1:]
if not args:
- args = ["-"]
+ args = ["-"]
for arg in args:
- if decompress:
- if arg == "-":
- f = GzipFile(filename="", mode="rb", fileobj=sys.stdin)
- g = sys.stdout
- else:
- if arg[-3:] != ".gz":
- print "filename doesn't end in .gz:", `arg`
- continue
- f = open(arg, "rb")
- g = __builtin__.open(arg[:-3], "wb")
- else:
- if arg == "-":
- f = sys.stdin
- g = GzipFile(filename="", mode="wb", fileobj=sys.stdout)
- else:
- f = __builtin__.open(arg, "rb")
- g = open(arg + ".gz", "wb")
- while 1:
- chunk = f.read(1024)
- if not chunk:
- break
- g.write(chunk)
- if g is not sys.stdout:
- g.close()
- if f is not sys.stdin:
- f.close()
+ if decompress:
+ if arg == "-":
+ f = GzipFile(filename="", mode="rb", fileobj=sys.stdin)
+ g = sys.stdout
+ else:
+ if arg[-3:] != ".gz":
+ print "filename doesn't end in .gz:", `arg`
+ continue
+ f = open(arg, "rb")
+ g = __builtin__.open(arg[:-3], "wb")
+ else:
+ if arg == "-":
+ f = sys.stdin
+ g = GzipFile(filename="", mode="wb", fileobj=sys.stdout)
+ else:
+ f = __builtin__.open(arg, "rb")
+ g = open(arg + ".gz", "wb")
+ while 1:
+ chunk = f.read(1024)
+ if not chunk:
+ break
+ g.write(chunk)
+ if g is not sys.stdout:
+ g.close()
+ if f is not sys.stdin:
+ f.close()
if __name__ == '__main__':
_test()
def handle_data(self, data):
if self.savedata is not None:
- self.savedata = self.savedata + data
+ self.savedata = self.savedata + data
else:
- if self.nofill:
- self.formatter.add_literal_data(data)
- else:
- self.formatter.add_flowing_data(data)
+ if self.nofill:
+ self.formatter.add_literal_data(data)
+ else:
+ self.formatter.add_flowing_data(data)
# --- Hooks to save data; shouldn't need to be overridden
def save_end(self):
data = self.savedata
self.savedata = None
- if not self.nofill:
- data = string.join(string.split(data))
- return data
+ if not self.nofill:
+ data = string.join(string.split(data))
+ return data
# --- Hooks for anchors; should probably be overridden
def anchor_bgn(self, href, name, type):
self.anchor = href
if self.anchor:
- self.anchorlist.append(href)
+ self.anchorlist.append(href)
def anchor_end(self):
if self.anchor:
- self.handle_data("[%d]" % len(self.anchorlist))
- self.anchor = None
+ self.handle_data("[%d]" % len(self.anchorlist))
+ self.anchor = None
# --- Hook for images; should probably be overridden
def do_li(self, attrs):
self.formatter.end_paragraph(0)
if self.list_stack:
- [dummy, label, counter] = top = self.list_stack[-1]
- top[2] = counter = counter+1
+ [dummy, label, counter] = top = self.list_stack[-1]
+ top[2] = counter = counter+1
else:
- label, counter = '*', 0
+ label, counter = '*', 0
self.formatter.add_label_data(label, counter)
def start_ol(self, attrs):
label = '1.'
for a, v in attrs:
if a == 'type':
- if len(v) == 1: v = v + '.'
- label = v
+ if len(v) == 1: v = v + '.'
+ label = v
self.list_stack.append(['ol', label, 0])
def end_ol(self):
self.formatter.end_paragraph(bl)
if self.list_stack:
if self.list_stack[-1][0] == 'dd':
- del self.list_stack[-1]
- self.formatter.pop_margin()
+ del self.list_stack[-1]
+ self.formatter.pop_margin()
# --- Phrase Markup
# Typographic Elements
def start_i(self, attrs):
- self.formatter.push_font((AS_IS, 1, AS_IS, AS_IS))
+ self.formatter.push_font((AS_IS, 1, AS_IS, AS_IS))
def end_i(self):
- self.formatter.pop_font()
+ self.formatter.pop_font()
def start_b(self, attrs):
- self.formatter.push_font((AS_IS, AS_IS, 1, AS_IS))
+ self.formatter.push_font((AS_IS, AS_IS, 1, AS_IS))
def end_b(self):
- self.formatter.pop_font()
+ self.formatter.pop_font()
def start_tt(self, attrs):
- self.formatter.push_font((AS_IS, AS_IS, AS_IS, 1))
+ self.formatter.push_font((AS_IS, AS_IS, AS_IS, 1))
def end_tt(self):
- self.formatter.pop_font()
+ self.formatter.pop_font()
def start_a(self, attrs):
href = ''
name = ''
type = ''
for attrname, value in attrs:
- value = string.strip(value)
+ value = string.strip(value)
if attrname == 'href':
href = value
if attrname == 'name':
alt = '(image)'
ismap = ''
src = ''
- width = 0
- height = 0
+ width = 0
+ height = 0
for attrname, value in attrs:
if attrname == 'align':
align = value
ismap = value
if attrname == 'src':
src = value
- if attrname == 'width':
- try: width = string.atoi(value)
- except: pass
- if attrname == 'height':
- try: height = string.atoi(value)
- except: pass
+ if attrname == 'width':
+ try: width = string.atoi(value)
+ except: pass
+ if attrname == 'height':
+ try: height = string.atoi(value)
+ except: pass
self.handle_image(src, alt, ismap, align, width, height)
# --- Really Old Unofficial Deprecated Stuff
import sys, formatter
if not args:
- args = sys.argv[1:]
+ args = sys.argv[1:]
silent = args and args[0] == '-s'
if silent:
- del args[0]
+ del args[0]
if args:
- file = args[0]
+ file = args[0]
else:
- file = 'test.html'
+ file = 'test.html'
if file == '-':
- f = sys.stdin
+ f = sys.stdin
else:
- try:
- f = open(file, 'r')
- except IOError, msg:
- print file, ":", msg
- sys.exit(1)
+ try:
+ f = open(file, 'r')
+ except IOError, msg:
+ print file, ":", msg
+ sys.exit(1)
data = f.read()
if f is not sys.stdin:
- f.close()
+ f.close()
if silent:
- f = formatter.NullFormatter()
+ f = formatter.NullFormatter()
else:
- f = formatter.AbstractFormatter(formatter.DumbWriter())
+ f = formatter.AbstractFormatter(formatter.DumbWriter())
p = HTMLParser(f)
p.feed(data)
class _Verbose:
def __init__(self, verbose = 0):
- self.verbose = verbose
+ self.verbose = verbose
def get_verbose(self):
- return self.verbose
+ return self.verbose
def set_verbose(self, verbose):
- self.verbose = verbose
+ self.verbose = verbose
# XXX The following is an experimental interface
def note(self, *args):
- if self.verbose:
- apply(self.message, args)
+ if self.verbose:
+ apply(self.message, args)
def message(self, format, *args):
- print format%args
+ print format%args
class BasicModuleLoader(_Verbose):
"""
def find_module(self, name, path = None):
- if path is None:
- path = [None] + self.default_path()
- for dir in path:
- stuff = self.find_module_in_dir(name, dir)
- if stuff: return stuff
- return None
+ if path is None:
+ path = [None] + self.default_path()
+ for dir in path:
+ stuff = self.find_module_in_dir(name, dir)
+ if stuff: return stuff
+ return None
def default_path(self):
- return sys.path
+ return sys.path
def find_module_in_dir(self, name, dir):
- if dir is None:
- return self.find_builtin_module(name)
- else:
- try:
- return imp.find_module(name, [dir])
- except ImportError:
- return None
+ if dir is None:
+ return self.find_builtin_module(name)
+ else:
+ try:
+ return imp.find_module(name, [dir])
+ except ImportError:
+ return None
def find_builtin_module(self, name):
- if imp.is_builtin(name):
- return None, '', ('', '', BUILTIN_MODULE)
- if imp.is_frozen(name):
- return None, '', ('', '', FROZEN_MODULE)
- return None
+ if imp.is_builtin(name):
+ return None, '', ('', '', BUILTIN_MODULE)
+ if imp.is_frozen(name):
+ return None, '', ('', '', FROZEN_MODULE)
+ return None
def load_module(self, name, stuff):
- file, filename, (suff, mode, type) = stuff
- try:
- if type == BUILTIN_MODULE:
- return imp.init_builtin(name)
- if type == FROZEN_MODULE:
- return imp.init_frozen(name)
- if type == C_EXTENSION:
- return imp.load_dynamic(name, filename, file)
- if type == PY_SOURCE:
- return imp.load_source(name, filename, file)
- if type == PY_COMPILED:
- return imp.load_compiled(name, filename, file)
- finally:
- if file: file.close()
- raise ImportError, "Unrecognized module type (%s) for %s" % \
- (`type`, name)
+ file, filename, (suff, mode, type) = stuff
+ try:
+ if type == BUILTIN_MODULE:
+ return imp.init_builtin(name)
+ if type == FROZEN_MODULE:
+ return imp.init_frozen(name)
+ if type == C_EXTENSION:
+ return imp.load_dynamic(name, filename, file)
+ if type == PY_SOURCE:
+ return imp.load_source(name, filename, file)
+ if type == PY_COMPILED:
+ return imp.load_compiled(name, filename, file)
+ finally:
+ if file: file.close()
+ raise ImportError, "Unrecognized module type (%s) for %s" % \
+ (`type`, name)
class Hooks(_Verbose):
def init_frozen(self, name): return imp.init_frozen(name)
def get_frozen_object(self, name): return imp.get_frozen_object(name)
def load_source(self, name, filename, file=None):
- return imp.load_source(name, filename, file)
+ return imp.load_source(name, filename, file)
def load_compiled(self, name, filename, file=None):
- return imp.load_compiled(name, filename, file)
+ return imp.load_compiled(name, filename, file)
def load_dynamic(self, name, filename, file=None):
- return imp.load_dynamic(name, filename, file)
+ return imp.load_dynamic(name, filename, file)
def add_module(self, name):
- d = self.modules_dict()
- if d.has_key(name): return d[name]
- d[name] = m = self.new_module(name)
- return m
+ d = self.modules_dict()
+ if d.has_key(name): return d[name]
+ d[name] = m = self.new_module(name)
+ return m
# sys interface
def modules_dict(self): return sys.modules
"""
def __init__(self, hooks = None, verbose = 0):
- BasicModuleLoader.__init__(self, verbose)
- self.hooks = hooks or Hooks(verbose)
+ BasicModuleLoader.__init__(self, verbose)
+ self.hooks = hooks or Hooks(verbose)
def default_path(self):
- return self.hooks.default_path()
+ return self.hooks.default_path()
def modules_dict(self):
- return self.hooks.modules_dict()
+ return self.hooks.modules_dict()
def get_hooks(self):
- return self.hooks
+ return self.hooks
def set_hooks(self, hooks):
- self.hooks = hooks
+ self.hooks = hooks
def find_builtin_module(self, name):
- if self.hooks.is_builtin(name):
- return None, '', ('', '', BUILTIN_MODULE)
- if self.hooks.is_frozen(name):
- return None, '', ('', '', FROZEN_MODULE)
- return None
+ if self.hooks.is_builtin(name):
+ return None, '', ('', '', BUILTIN_MODULE)
+ if self.hooks.is_frozen(name):
+ return None, '', ('', '', FROZEN_MODULE)
+ return None
def find_module_in_dir(self, name, dir):
- if dir is None:
- return self.find_builtin_module(name)
- for info in self.hooks.get_suffixes():
- suff, mode, type = info
- fullname = self.hooks.path_join(dir, name+suff)
- try:
- fp = self.hooks.openfile(fullname, mode)
- return fp, fullname, info
- except self.hooks.openfile_error:
- pass
- return None
+ if dir is None:
+ return self.find_builtin_module(name)
+ for info in self.hooks.get_suffixes():
+ suff, mode, type = info
+ fullname = self.hooks.path_join(dir, name+suff)
+ try:
+ fp = self.hooks.openfile(fullname, mode)
+ return fp, fullname, info
+ except self.hooks.openfile_error:
+ pass
+ return None
def load_module(self, name, stuff):
- file, filename, (suff, mode, type) = stuff
- try:
- if type == BUILTIN_MODULE:
- return self.hooks.init_builtin(name)
- if type == FROZEN_MODULE:
- return self.hooks.init_frozen(name)
- if type == C_EXTENSION:
- m = self.hooks.load_dynamic(name, filename, file)
- elif type == PY_SOURCE:
- m = self.hooks.load_source(name, filename, file)
- elif type == PY_COMPILED:
- m = self.hooks.load_compiled(name, filename, file)
- else:
- raise ImportError, "Unrecognized module type (%s) for %s" % \
- (`type`, name)
- finally:
- if file: file.close()
- m.__file__ = filename
- return m
+ file, filename, (suff, mode, type) = stuff
+ try:
+ if type == BUILTIN_MODULE:
+ return self.hooks.init_builtin(name)
+ if type == FROZEN_MODULE:
+ return self.hooks.init_frozen(name)
+ if type == C_EXTENSION:
+ m = self.hooks.load_dynamic(name, filename, file)
+ elif type == PY_SOURCE:
+ m = self.hooks.load_source(name, filename, file)
+ elif type == PY_COMPILED:
+ m = self.hooks.load_compiled(name, filename, file)
+ else:
+ raise ImportError, "Unrecognized module type (%s) for %s" % \
+ (`type`, name)
+ finally:
+ if file: file.close()
+ m.__file__ = filename
+ return m
class FancyModuleLoader(ModuleLoader):
"""Fancy module loader -- parses and execs the code itself."""
def load_module(self, name, stuff):
- file, filename, (suff, mode, type) = stuff
- if type == FROZEN_MODULE:
- code = self.hooks.get_frozen_object(name)
- elif type == PY_COMPILED:
- import marshal
- file.seek(8)
- code = marshal.load(file)
- elif type == PY_SOURCE:
- data = file.read()
- code = compile(data, filename, 'exec')
- else:
- return ModuleLoader.load_module(self, name, stuff)
- m = self.hooks.add_module(name)
- m.__file__ = filename
- exec code in m.__dict__
- return m
+ file, filename, (suff, mode, type) = stuff
+ if type == FROZEN_MODULE:
+ code = self.hooks.get_frozen_object(name)
+ elif type == PY_COMPILED:
+ import marshal
+ file.seek(8)
+ code = marshal.load(file)
+ elif type == PY_SOURCE:
+ data = file.read()
+ code = compile(data, filename, 'exec')
+ else:
+ return ModuleLoader.load_module(self, name, stuff)
+ m = self.hooks.add_module(name)
+ m.__file__ = filename
+ exec code in m.__dict__
+ return m
class ModuleImporter(_Verbose):
"""
def __init__(self, loader = None, verbose = 0):
- _Verbose.__init__(self, verbose)
- self.loader = loader or ModuleLoader(None, verbose)
- self.modules = self.loader.modules_dict()
+ _Verbose.__init__(self, verbose)
+ self.loader = loader or ModuleLoader(None, verbose)
+ self.modules = self.loader.modules_dict()
def get_loader(self):
- return self.loader
+ return self.loader
def set_loader(self, loader):
- self.loader = loader
+ self.loader = loader
def get_hooks(self):
- return self.loader.get_hooks()
+ return self.loader.get_hooks()
def set_hooks(self, hooks):
- return self.loader.set_hooks(hooks)
+ return self.loader.set_hooks(hooks)
def import_module(self, name, globals={}, locals={}, fromlist=[]):
- if self.modules.has_key(name):
- return self.modules[name] # Fast path
- stuff = self.loader.find_module(name)
- if not stuff:
- raise ImportError, "No module named %s" % name
- return self.loader.load_module(name, stuff)
+ if self.modules.has_key(name):
+ return self.modules[name] # Fast path
+ stuff = self.loader.find_module(name)
+ if not stuff:
+ raise ImportError, "No module named %s" % name
+ return self.loader.load_module(name, stuff)
def reload(self, module, path = None):
- name = module.__name__
- stuff = self.loader.find_module(name, path)
- if not stuff:
- raise ImportError, "Module %s not found for reload" % name
- return self.loader.load_module(name, stuff)
+ name = module.__name__
+ stuff = self.loader.find_module(name, path)
+ if not stuff:
+ raise ImportError, "Module %s not found for reload" % name
+ return self.loader.load_module(name, stuff)
def unload(self, module):
- del self.modules[module.__name__]
- # XXX Should this try to clear the module's namespace?
+ del self.modules[module.__name__]
+ # XXX Should this try to clear the module's namespace?
def install(self):
- self.save_import_module = __builtin__.__import__
- self.save_reload = __builtin__.reload
- if not hasattr(__builtin__, 'unload'):
- __builtin__.unload = None
- self.save_unload = __builtin__.unload
- __builtin__.__import__ = self.import_module
- __builtin__.reload = self.reload
- __builtin__.unload = self.unload
+ self.save_import_module = __builtin__.__import__
+ self.save_reload = __builtin__.reload
+ if not hasattr(__builtin__, 'unload'):
+ __builtin__.unload = None
+ self.save_unload = __builtin__.unload
+ __builtin__.__import__ = self.import_module
+ __builtin__.reload = self.reload
+ __builtin__.unload = self.unload
def uninstall(self):
- __builtin__.__import__ = self.save_import_module
- __builtin__.reload = self.save_reload
- __builtin__.unload = self.save_unload
- if not __builtin__.unload:
- del __builtin__.unload
+ __builtin__.__import__ = self.save_import_module
+ __builtin__.reload = self.save_reload
+ __builtin__.unload = self.save_unload
+ if not __builtin__.unload:
+ del __builtin__.unload
default_importer = None
while 1:
line = fp.readline()
if not line: break
- if string.find(line, '{1, "') > -1:
- match = strprog.search(line)
- if match:
- lines.append(" '" + match.group(1) + "',\n")
+ if string.find(line, '{1, "') > -1:
+ match = strprog.search(line)
+ if match:
+ lines.append(" '" + match.group(1) + "',\n")
fp.close()
lines.sort()
q, tail = find_head_package(parent, name)
m = load_tail(q, tail)
if not fromlist:
- return q
+ return q
if hasattr(m, "__path__"):
- ensure_fromlist(m, fromlist)
+ ensure_fromlist(m, fromlist)
return m
def determine_parent(globals):
if not globals or not globals.has_key("__name__"):
- return None
+ return None
pname = globals['__name__']
if globals.has_key("__path__"):
- parent = sys.modules[pname]
- assert globals is parent.__dict__
- return parent
+ parent = sys.modules[pname]
+ assert globals is parent.__dict__
+ return parent
if '.' in pname:
- i = string.rfind(pname, '.')
- pname = pname[:i]
- parent = sys.modules[pname]
- assert parent.__name__ == pname
- return parent
+ i = string.rfind(pname, '.')
+ pname = pname[:i]
+ parent = sys.modules[pname]
+ assert parent.__name__ == pname
+ return parent
return None
def find_head_package(parent, name):
if '.' in name:
- i = string.find(name, '.')
- head = name[:i]
- tail = name[i+1:]
+ i = string.find(name, '.')
+ head = name[:i]
+ tail = name[i+1:]
else:
- head = name
- tail = ""
+ head = name
+ tail = ""
if parent:
- qname = "%s.%s" % (parent.__name__, head)
+ qname = "%s.%s" % (parent.__name__, head)
else:
- qname = head
+ qname = head
q = import_module(head, qname, parent)
if q: return q, tail
if parent:
- qname = head
- parent = None
- q = import_module(head, qname, parent)
- if q: return q, tail
+ qname = head
+ parent = None
+ q = import_module(head, qname, parent)
+ if q: return q, tail
raise ImportError, "No module named " + qname
def load_tail(q, tail):
m = q
while tail:
- i = string.find(tail, '.')
- if i < 0: i = len(tail)
- head, tail = tail[:i], tail[i+1:]
- mname = "%s.%s" % (m.__name__, head)
- m = import_module(head, mname, m)
- if not m:
- raise ImportError, "No module named " + mname
+ i = string.find(tail, '.')
+ if i < 0: i = len(tail)
+ head, tail = tail[:i], tail[i+1:]
+ mname = "%s.%s" % (m.__name__, head)
+ m = import_module(head, mname, m)
+ if not m:
+ raise ImportError, "No module named " + mname
return m
def ensure_fromlist(m, fromlist, recursive=0):
for sub in fromlist:
- if sub == "*":
- if not recursive:
- try:
- all = m.__all__
- except AttributeError:
- pass
- else:
- ensure_fromlist(m, all, 1)
- continue
- if sub != "*" and not hasattr(m, sub):
- subname = "%s.%s" % (m.__name__, sub)
- submod = import_module(sub, subname, m)
- if not submod:
- raise ImportError, "No module named " + subname
+ if sub == "*":
+ if not recursive:
+ try:
+ all = m.__all__
+ except AttributeError:
+ pass
+ else:
+ ensure_fromlist(m, all, 1)
+ continue
+ if sub != "*" and not hasattr(m, sub):
+ subname = "%s.%s" % (m.__name__, sub)
+ submod = import_module(sub, subname, m)
+ if not submod:
+ raise ImportError, "No module named " + subname
def import_module(partname, fqname, parent):
try:
- return sys.modules[fqname]
+ return sys.modules[fqname]
except KeyError:
- pass
+ pass
try:
- fp, pathname, stuff = imp.find_module(partname,
- parent and parent.__path__)
+ fp, pathname, stuff = imp.find_module(partname,
+ parent and parent.__path__)
except ImportError:
- return None
+ return None
try:
- m = imp.load_module(fqname, fp, pathname, stuff)
+ m = imp.load_module(fqname, fp, pathname, stuff)
finally:
- if fp: fp.close()
+ if fp: fp.close()
if parent:
- setattr(parent, partname, m)
+ setattr(parent, partname, m)
return m
def reload_hook(module):
name = module.__name__
if '.' not in name:
- return import_module(name, name, None)
+ return import_module(name, name, None)
i = string.rfind(name, '.')
pname = name[:i]
parent = sys.modules[pname]
if not grouping:return s
result=""
while s and grouping:
- # if grouping is -1, we are done
- if grouping[0]==CHAR_MAX:
- break
- # 0: re-use last group ad infinitum
- elif grouping[0]!=0:
- #process last group
- group=grouping[0]
- grouping=grouping[1:]
- if result:
- result=s[-group:]+conv['thousands_sep']+result
- else:
- result=s[-group:]
- s=s[:-group]
+ # if grouping is -1, we are done
+ if grouping[0]==CHAR_MAX:
+ break
+ # 0: re-use last group ad infinitum
+ elif grouping[0]!=0:
+ #process last group
+ group=grouping[0]
+ grouping=grouping[1:]
+ if result:
+ result=s[-group:]+conv['thousands_sep']+result
+ else:
+ result=s[-group:]
+ s=s[:-group]
if s and result:
- result=s+conv['thousands_sep']+result
+ result=s+conv['thousands_sep']+result
return result
def format(f,val,grouping=0):
result = f % val
fields = string.splitfields(result,".")
if grouping:
- fields[0]=_group(fields[0])
+ fields[0]=_group(fields[0])
if len(fields)==2:
- return fields[0]+localeconv()['decimal_point']+fields[1]
+ return fields[0]+localeconv()['decimal_point']+fields[1]
elif len(fields)==1:
- return fields[0]
+ return fields[0]
else:
- raise Error,"Too many decimal points in result string"
+ raise Error,"Too many decimal points in result string"
def str(val):
"""Convert float to integer, taking the locale into account."""
#
tp = urllib.splittype(pathname)[0]
if tp and tp <> 'file':
- raise RuntimeError, 'Cannot convert non-local URL to pathname'
+ raise RuntimeError, 'Cannot convert non-local URL to pathname'
components = string.split(pathname, '/')
# Remove . and embedded ..
i = 0
while i < len(components):
- if components[i] == '.':
- del components[i]
- elif components[i] == '..' and i > 0 and \
- components[i-1] not in ('', '..'):
- del components[i-1:i+1]
- i = i-1
- elif components[i] == '' and i > 0 and components[i-1] <> '':
- del components[i]
- else:
- i = i+1
+ if components[i] == '.':
+ del components[i]
+ elif components[i] == '..' and i > 0 and \
+ components[i-1] not in ('', '..'):
+ del components[i-1:i+1]
+ i = i-1
+ elif components[i] == '' and i > 0 and components[i-1] <> '':
+ del components[i]
+ else:
+ i = i+1
if not components[0]:
- # Absolute unix path, don't start with colon
- return string.join(components[1:], ':')
+ # Absolute unix path, don't start with colon
+ return string.join(components[1:], ':')
else:
- # relative unix path, start with colon. First replace
- # leading .. by empty strings (giving ::file)
- i = 0
- while i < len(components) and components[i] == '..':
- components[i] = ''
- i = i + 1
- return ':' + string.join(components, ':')
+ # relative unix path, start with colon. First replace
+ # leading .. by empty strings (giving ::file)
+ i = 0
+ while i < len(components) and components[i] == '..':
+ components[i] = ''
+ i = i + 1
+ return ':' + string.join(components, ':')
def pathname2url(pathname):
"convert mac pathname to /-delimited pathname"
if '/' in pathname:
- raise RuntimeError, "Cannot convert pathname containing slashes"
+ raise RuntimeError, "Cannot convert pathname containing slashes"
components = string.split(pathname, ':')
# Remove empty first and/or last component
if components[0] == '':
- del components[0]
+ del components[0]
if components[-1] == '':
- del components[-1]
+ del components[-1]
# Replace empty string ('::') by .. (will result in '/../' later)
for i in range(len(components)):
- if components[i] == '':
- components[i] = '..'
+ if components[i] == '':
+ components[i] = '..'
# Truncate names longer than 31 bytes
components = map(lambda x: x[:31], components)
if os.path.isabs(pathname):
- return '/' + string.join(components, '/')
+ return '/' + string.join(components, '/')
else:
- return string.join(components, '/')
+ return string.join(components, '/')
def test():
for url in ["index.html",
- "bar/index.html",
- "/foo/bar/index.html",
- "/foo/bar/",
- "/"]:
- print `url`, '->', `url2pathname(url)`
+ "bar/index.html",
+ "/foo/bar/index.html",
+ "/foo/bar/",
+ "/"]:
+ print `url`, '->', `url2pathname(url)`
for path in ["drive:",
- "drive:dir:",
- "drive:dir:file",
- "drive:file",
- "file",
- ":file",
- ":dir:",
- ":dir:file"]:
- print `path`, '->', `pathname2url(path)`
+ "drive:dir:",
+ "drive:dir:file",
+ "drive:file",
+ "file",
+ ":file",
+ ":dir:",
+ ":dir:file"]:
+ print `path`, '->', `pathname2url(path)`
if __name__ == '__main__':
test()
"""
caps = {}
for mailcap in listmailcapfiles():
- try:
- fp = open(mailcap, 'r')
- except:
- continue
- morecaps = readmailcapfile(fp)
- fp.close()
- for key in morecaps.keys():
- if not caps.has_key(key):
- caps[key] = morecaps[key]
- else:
- caps[key] = caps[key] + morecaps[key]
+ try:
+ fp = open(mailcap, 'r')
+ except:
+ continue
+ morecaps = readmailcapfile(fp)
+ fp.close()
+ for key in morecaps.keys():
+ if not caps.has_key(key):
+ caps[key] = morecaps[key]
+ else:
+ caps[key] = caps[key] + morecaps[key]
return caps
def listmailcapfiles():
"""Return a list of all mailcap files found on the system."""
# XXX Actually, this is Unix-specific
if os.environ.has_key('MAILCAPS'):
- str = os.environ['MAILCAPS']
- mailcaps = string.splitfields(str, ':')
+ str = os.environ['MAILCAPS']
+ mailcaps = string.splitfields(str, ':')
else:
- if os.environ.has_key('HOME'):
- home = os.environ['HOME']
- else:
- # Don't bother with getpwuid()
- home = '.' # Last resort
- mailcaps = [home + '/.mailcap', '/etc/mailcap',
- '/usr/etc/mailcap', '/usr/local/etc/mailcap']
+ if os.environ.has_key('HOME'):
+ home = os.environ['HOME']
+ else:
+ # Don't bother with getpwuid()
+ home = '.' # Last resort
+ mailcaps = [home + '/.mailcap', '/etc/mailcap',
+ '/usr/etc/mailcap', '/usr/local/etc/mailcap']
return mailcaps
def readmailcapfile(fp):
caps = {}
while 1:
- line = fp.readline()
- if not line: break
- # Ignore comments and blank lines
- if line[0] == '#' or string.strip(line) == '':
- continue
- nextline = line
- # Join continuation lines
- while nextline[-2:] == '\\\n':
- nextline = fp.readline()
- if not nextline: nextline = '\n'
- line = line[:-2] + nextline
- # Parse the line
- key, fields = parseline(line)
- if not (key and fields):
- continue
- # Normalize the key
- types = string.splitfields(key, '/')
- for j in range(len(types)):
- types[j] = string.strip(types[j])
- key = string.lower(string.joinfields(types, '/'))
- # Update the database
- if caps.has_key(key):
- caps[key].append(fields)
- else:
- caps[key] = [fields]
+ line = fp.readline()
+ if not line: break
+ # Ignore comments and blank lines
+ if line[0] == '#' or string.strip(line) == '':
+ continue
+ nextline = line
+ # Join continuation lines
+ while nextline[-2:] == '\\\n':
+ nextline = fp.readline()
+ if not nextline: nextline = '\n'
+ line = line[:-2] + nextline
+ # Parse the line
+ key, fields = parseline(line)
+ if not (key and fields):
+ continue
+ # Normalize the key
+ types = string.splitfields(key, '/')
+ for j in range(len(types)):
+ types[j] = string.strip(types[j])
+ key = string.lower(string.joinfields(types, '/'))
+ # Update the database
+ if caps.has_key(key):
+ caps[key].append(fields)
+ else:
+ caps[key] = [fields]
return caps
def parseline(line):
fields = []
i, n = 0, len(line)
while i < n:
- field, i = parsefield(line, i, n)
- fields.append(field)
- i = i+1 # Skip semicolon
+ field, i = parsefield(line, i, n)
+ fields.append(field)
+ i = i+1 # Skip semicolon
if len(fields) < 2:
- return None, None
+ return None, None
key, view, rest = fields[0], fields[1], fields[2:]
fields = {'view': view}
for field in rest:
- i = string.find(field, '=')
- if i < 0:
- fkey = field
- fvalue = ""
- else:
- fkey = string.strip(field[:i])
- fvalue = string.strip(field[i+1:])
- if fields.has_key(fkey):
- # Ignore it
- pass
- else:
- fields[fkey] = fvalue
+ i = string.find(field, '=')
+ if i < 0:
+ fkey = field
+ fvalue = ""
+ else:
+ fkey = string.strip(field[:i])
+ fvalue = string.strip(field[i+1:])
+ if fields.has_key(fkey):
+ # Ignore it
+ pass
+ else:
+ fields[fkey] = fvalue
return key, fields
def parsefield(line, i, n):
start = i
while i < n:
- c = line[i]
- if c == ';':
- break
- elif c == '\\':
- i = i+2
- else:
- i = i+1
+ c = line[i]
+ if c == ';':
+ break
+ elif c == '\\':
+ i = i+2
+ else:
+ i = i+1
return string.strip(line[start:i]), i
entries = lookup(caps, MIMEtype, key)
# XXX This code should somehow check for the needsterminal flag.
for e in entries:
- if e.has_key('test'):
- test = subst(e['test'], filename, plist)
- if test and os.system(test) != 0:
- continue
- command = subst(e[key], MIMEtype, filename, plist)
- return command, e
+ if e.has_key('test'):
+ test = subst(e['test'], filename, plist)
+ if test and os.system(test) != 0:
+ continue
+ command = subst(e[key], MIMEtype, filename, plist)
+ return command, e
return None, None
def lookup(caps, MIMEtype, key=None):
entries = []
if caps.has_key(MIMEtype):
- entries = entries + caps[MIMEtype]
+ entries = entries + caps[MIMEtype]
MIMEtypes = string.splitfields(MIMEtype, '/')
MIMEtype = MIMEtypes[0] + '/*'
if caps.has_key(MIMEtype):
- entries = entries + caps[MIMEtype]
+ entries = entries + caps[MIMEtype]
if key is not None:
- entries = filter(lambda e, key=key: e.has_key(key), entries)
+ entries = filter(lambda e, key=key: e.has_key(key), entries)
return entries
def subst(field, MIMEtype, filename, plist=[]):
res = ''
i, n = 0, len(field)
while i < n:
- c = field[i]; i = i+1
- if c <> '%':
- if c == '\\':
- c = field[i:i+1]; i = i+1
- res = res + c
- else:
- c = field[i]; i = i+1
- if c == '%':
- res = res + c
- elif c == 's':
- res = res + filename
- elif c == 't':
- res = res + MIMEtype
- elif c == '{':
- start = i
- while i < n and field[i] <> '}':
- i = i+1
- name = field[start:i]
- i = i+1
- res = res + findparam(name, plist)
- # XXX To do:
- # %n == number of parts if type is multipart/*
- # %F == list of alternating type and filename for parts
- else:
- res = res + '%' + c
+ c = field[i]; i = i+1
+ if c <> '%':
+ if c == '\\':
+ c = field[i:i+1]; i = i+1
+ res = res + c
+ else:
+ c = field[i]; i = i+1
+ if c == '%':
+ res = res + c
+ elif c == 's':
+ res = res + filename
+ elif c == 't':
+ res = res + MIMEtype
+ elif c == '{':
+ start = i
+ while i < n and field[i] <> '}':
+ i = i+1
+ name = field[start:i]
+ i = i+1
+ res = res + findparam(name, plist)
+ # XXX To do:
+ # %n == number of parts if type is multipart/*
+ # %F == list of alternating type and filename for parts
+ else:
+ res = res + '%' + c
return res
def findparam(name, plist):
name = string.lower(name) + '='
n = len(name)
for p in plist:
- if string.lower(p[:n]) == name:
- return p[n:]
+ if string.lower(p[:n]) == name:
+ return p[n:]
return ''
import sys
caps = getcaps()
if not sys.argv[1:]:
- show(caps)
- return
+ show(caps)
+ return
for i in range(1, len(sys.argv), 2):
- args = sys.argv[i:i+2]
- if len(args) < 2:
- print "usage: mailcap [MIMEtype file] ..."
- return
- MIMEtype = args[0]
- file = args[1]
- command, e = findmatch(caps, MIMEtype, 'view', file)
- if not command:
- print "No viewer found for", type
- else:
- print "Executing:", command
- sts = os.system(command)
- if sts:
- print "Exit status:", sts
+ args = sys.argv[i:i+2]
+ if len(args) < 2:
+ print "usage: mailcap [MIMEtype file] ..."
+ return
+ MIMEtype = args[0]
+ file = args[1]
+ command, e = findmatch(caps, MIMEtype, 'view', file)
+ if not command:
+ print "No viewer found for", type
+ else:
+ print "Executing:", command
+ sts = os.system(command)
+ if sts:
+ print "Exit status:", sts
def show(caps):
print "Mailcap files:"
ckeys = caps.keys()
ckeys.sort()
for type in ckeys:
- print type
- entries = caps[type]
- for e in entries:
- keys = e.keys()
- keys.sort()
- for k in keys:
- print " %-15s" % k, e[k]
- print
+ print type
+ entries = caps[type]
+ for e in entries:
+ keys = e.keys()
+ keys.sort()
+ for k in keys:
+ print " %-15s" % k, e[k]
+ print
if __name__ == '__main__':
test()
# Constructor
def __init__(self, path = None, profile = None):
- if not profile: profile = MH_PROFILE
- self.profile = os.path.expanduser(profile)
- if not path: path = self.getprofile('Path')
- if not path: path = PATH
- if not os.path.isabs(path) and path[0] != '~':
- path = os.path.join('~', path)
- path = os.path.expanduser(path)
- if not os.path.isdir(path): raise Error, 'MH() path not found'
- self.path = path
+ if not profile: profile = MH_PROFILE
+ self.profile = os.path.expanduser(profile)
+ if not path: path = self.getprofile('Path')
+ if not path: path = PATH
+ if not os.path.isabs(path) and path[0] != '~':
+ path = os.path.join('~', path)
+ path = os.path.expanduser(path)
+ if not os.path.isdir(path): raise Error, 'MH() path not found'
+ self.path = path
# String representation
def __repr__(self):
- return 'MH(%s, %s)' % (`self.path`, `self.profile`)
+ return 'MH(%s, %s)' % (`self.path`, `self.profile`)
# Routine to print an error. May be overridden by a derived class
def error(self, msg, *args):
- sys.stderr.write('MH error: %s\n' % (msg % args))
+ sys.stderr.write('MH error: %s\n' % (msg % args))
# Return a profile entry, None if not found
def getprofile(self, key):
- return pickline(self.profile, key)
+ return pickline(self.profile, key)
# Return the path (the name of the collection's directory)
def getpath(self):
- return self.path
+ return self.path
# Return the name of the current folder
def getcontext(self):
- context = pickline(os.path.join(self.getpath(), 'context'),
- 'Current-Folder')
- if not context: context = 'inbox'
- return context
+ context = pickline(os.path.join(self.getpath(), 'context'),
+ 'Current-Folder')
+ if not context: context = 'inbox'
+ return context
# Set the name of the current folder
def setcontext(self, context):
- fn = os.path.join(self.getpath(), 'context')
- f = open(fn, "w")
- f.write("Current-Folder: %s\n" % context)
- f.close()
+ fn = os.path.join(self.getpath(), 'context')
+ f = open(fn, "w")
+ f.write("Current-Folder: %s\n" % context)
+ f.close()
# Return the names of the top-level folders
def listfolders(self):
- folders = []
- path = self.getpath()
- for name in os.listdir(path):
- fullname = os.path.join(path, name)
- if os.path.isdir(fullname):
- folders.append(name)
- folders.sort()
- return folders
+ folders = []
+ path = self.getpath()
+ for name in os.listdir(path):
+ fullname = os.path.join(path, name)
+ if os.path.isdir(fullname):
+ folders.append(name)
+ folders.sort()
+ return folders
# Return the names of the subfolders in a given folder
# (prefixed with the given folder name)
def listsubfolders(self, name):
- fullname = os.path.join(self.path, name)
- # Get the link count so we can avoid listing folders
- # that have no subfolders.
- st = os.stat(fullname)
- nlinks = st[ST_NLINK]
- if nlinks <= 2:
- return []
- subfolders = []
- subnames = os.listdir(fullname)
- for subname in subnames:
- fullsubname = os.path.join(fullname, subname)
- if os.path.isdir(fullsubname):
- name_subname = os.path.join(name, subname)
- subfolders.append(name_subname)
- # Stop looking for subfolders when
- # we've seen them all
- nlinks = nlinks - 1
- if nlinks <= 2:
- break
- subfolders.sort()
- return subfolders
+ fullname = os.path.join(self.path, name)
+ # Get the link count so we can avoid listing folders
+ # that have no subfolders.
+ st = os.stat(fullname)
+ nlinks = st[ST_NLINK]
+ if nlinks <= 2:
+ return []
+ subfolders = []
+ subnames = os.listdir(fullname)
+ for subname in subnames:
+ fullsubname = os.path.join(fullname, subname)
+ if os.path.isdir(fullsubname):
+ name_subname = os.path.join(name, subname)
+ subfolders.append(name_subname)
+ # Stop looking for subfolders when
+ # we've seen them all
+ nlinks = nlinks - 1
+ if nlinks <= 2:
+ break
+ subfolders.sort()
+ return subfolders
# Return the names of all folders, including subfolders, recursively
def listallfolders(self):
- return self.listallsubfolders('')
+ return self.listallsubfolders('')
# Return the names of subfolders in a given folder, recursively
def listallsubfolders(self, name):
- fullname = os.path.join(self.path, name)
- # Get the link count so we can avoid listing folders
- # that have no subfolders.
- st = os.stat(fullname)
- nlinks = st[ST_NLINK]
- if nlinks <= 2:
- return []
- subfolders = []
- subnames = os.listdir(fullname)
- for subname in subnames:
- if subname[0] == ',' or isnumeric(subname): continue
- fullsubname = os.path.join(fullname, subname)
- if os.path.isdir(fullsubname):
- name_subname = os.path.join(name, subname)
- subfolders.append(name_subname)
- if not os.path.islink(fullsubname):
- subsubfolders = self.listallsubfolders(
- name_subname)
- subfolders = subfolders + subsubfolders
- # Stop looking for subfolders when
- # we've seen them all
- nlinks = nlinks - 1
- if nlinks <= 2:
- break
- subfolders.sort()
- return subfolders
+ fullname = os.path.join(self.path, name)
+ # Get the link count so we can avoid listing folders
+ # that have no subfolders.
+ st = os.stat(fullname)
+ nlinks = st[ST_NLINK]
+ if nlinks <= 2:
+ return []
+ subfolders = []
+ subnames = os.listdir(fullname)
+ for subname in subnames:
+ if subname[0] == ',' or isnumeric(subname): continue
+ fullsubname = os.path.join(fullname, subname)
+ if os.path.isdir(fullsubname):
+ name_subname = os.path.join(name, subname)
+ subfolders.append(name_subname)
+ if not os.path.islink(fullsubname):
+ subsubfolders = self.listallsubfolders(
+ name_subname)
+ subfolders = subfolders + subsubfolders
+ # Stop looking for subfolders when
+ # we've seen them all
+ nlinks = nlinks - 1
+ if nlinks <= 2:
+ break
+ subfolders.sort()
+ return subfolders
# Return a new Folder object for the named folder
def openfolder(self, name):
- return Folder(self, name)
+ return Folder(self, name)
# Create a new folder. This raises os.error if the folder
# cannot be created
def makefolder(self, name):
- protect = pickline(self.profile, 'Folder-Protect')
- if protect and isnumeric(protect):
- mode = string.atoi(protect, 8)
- else:
- mode = FOLDER_PROTECT
- os.mkdir(os.path.join(self.getpath(), name), mode)
+ protect = pickline(self.profile, 'Folder-Protect')
+ if protect and isnumeric(protect):
+ mode = string.atoi(protect, 8)
+ else:
+ mode = FOLDER_PROTECT
+ os.mkdir(os.path.join(self.getpath(), name), mode)
# Delete a folder. This removes files in the folder but not
# subdirectories. If deleting the folder itself fails it
# raises os.error
def deletefolder(self, name):
- fullname = os.path.join(self.getpath(), name)
- for subname in os.listdir(fullname):
- fullsubname = os.path.join(fullname, subname)
- try:
- os.unlink(fullsubname)
- except os.error:
- self.error('%s not deleted, continuing...' %
- fullsubname)
- os.rmdir(fullname)
+ fullname = os.path.join(self.getpath(), name)
+ for subname in os.listdir(fullname):
+ fullsubname = os.path.join(fullname, subname)
+ try:
+ os.unlink(fullsubname)
+ except os.error:
+ self.error('%s not deleted, continuing...' %
+ fullsubname)
+ os.rmdir(fullname)
# Class representing a particular folder
# Constructor
def __init__(self, mh, name):
- self.mh = mh
- self.name = name
- if not os.path.isdir(self.getfullname()):
- raise Error, 'no folder %s' % name
+ self.mh = mh
+ self.name = name
+ if not os.path.isdir(self.getfullname()):
+ raise Error, 'no folder %s' % name
# String representation
def __repr__(self):
- return 'Folder(%s, %s)' % (`self.mh`, `self.name`)
+ return 'Folder(%s, %s)' % (`self.mh`, `self.name`)
# Error message handler
def error(self, *args):
- apply(self.mh.error, args)
+ apply(self.mh.error, args)
# Return the full pathname of the folder
def getfullname(self):
- return os.path.join(self.mh.path, self.name)
+ return os.path.join(self.mh.path, self.name)
# Return the full pathname of the folder's sequences file
def getsequencesfilename(self):
- return os.path.join(self.getfullname(), MH_SEQUENCES)
+ return os.path.join(self.getfullname(), MH_SEQUENCES)
# Return the full pathname of a message in the folder
def getmessagefilename(self, n):
- return os.path.join(self.getfullname(), str(n))
+ return os.path.join(self.getfullname(), str(n))
# Return list of direct subfolders
def listsubfolders(self):
- return self.mh.listsubfolders(self.name)
+ return self.mh.listsubfolders(self.name)
# Return list of all subfolders
def listallsubfolders(self):
- return self.mh.listallsubfolders(self.name)
+ return self.mh.listallsubfolders(self.name)
# Return the list of messages currently present in the folder.
# As a side effect, set self.last to the last message (or 0)
def listmessages(self):
- messages = []
- match = numericprog.match
- append = messages.append
- for name in os.listdir(self.getfullname()):
- if match(name) >= 0:
- append(name)
- messages = map(string.atoi, messages)
- messages.sort()
- if messages:
- self.last = messages[-1]
- else:
- self.last = 0
- return messages
+ messages = []
+ match = numericprog.match
+ append = messages.append
+ for name in os.listdir(self.getfullname()):
+ if match(name) >= 0:
+ append(name)
+ messages = map(string.atoi, messages)
+ messages.sort()
+ if messages:
+ self.last = messages[-1]
+ else:
+ self.last = 0
+ return messages
# Return the set of sequences for the folder
def getsequences(self):
- sequences = {}
- fullname = self.getsequencesfilename()
- try:
- f = open(fullname, 'r')
- except IOError:
- return sequences
- while 1:
- line = f.readline()
- if not line: break
- fields = string.splitfields(line, ':')
- if len(fields) <> 2:
- self.error('bad sequence in %s: %s' %
- (fullname, string.strip(line)))
- key = string.strip(fields[0])
- value = IntSet(string.strip(fields[1]), ' ').tolist()
- sequences[key] = value
- return sequences
+ sequences = {}
+ fullname = self.getsequencesfilename()
+ try:
+ f = open(fullname, 'r')
+ except IOError:
+ return sequences
+ while 1:
+ line = f.readline()
+ if not line: break
+ fields = string.splitfields(line, ':')
+ if len(fields) <> 2:
+ self.error('bad sequence in %s: %s' %
+ (fullname, string.strip(line)))
+ key = string.strip(fields[0])
+ value = IntSet(string.strip(fields[1]), ' ').tolist()
+ sequences[key] = value
+ return sequences
# Write the set of sequences back to the folder
def putsequences(self, sequences):
- fullname = self.getsequencesfilename()
- f = None
- for key in sequences.keys():
- s = IntSet('', ' ')
- s.fromlist(sequences[key])
- if not f: f = open(fullname, 'w')
- f.write('%s: %s\n' % (key, s.tostring()))
- if not f:
- try:
- os.unlink(fullname)
- except os.error:
- pass
- else:
- f.close()
+ fullname = self.getsequencesfilename()
+ f = None
+ for key in sequences.keys():
+ s = IntSet('', ' ')
+ s.fromlist(sequences[key])
+ if not f: f = open(fullname, 'w')
+ f.write('%s: %s\n' % (key, s.tostring()))
+ if not f:
+ try:
+ os.unlink(fullname)
+ except os.error:
+ pass
+ else:
+ f.close()
# Return the current message. Raise KeyError when there is none
def getcurrent(self):
- seqs = self.getsequences()
- try:
- return max(seqs['cur'])
- except (ValueError, KeyError):
- raise Error, "no cur message"
+ seqs = self.getsequences()
+ try:
+ return max(seqs['cur'])
+ except (ValueError, KeyError):
+ raise Error, "no cur message"
# Set the current message
def setcurrent(self, n):
- updateline(self.getsequencesfilename(), 'cur', str(n), 0)
+ updateline(self.getsequencesfilename(), 'cur', str(n), 0)
# Parse an MH sequence specification into a message list.
# Attempt to mimic mh-sequence(5) as close as possible.
# Also attempt to mimic observed behavior regarding which
# conditions cause which error messages
def parsesequence(self, seq):
- # XXX Still not complete (see mh-format(5)).
- # Missing are:
- # - 'prev', 'next' as count
- # - Sequence-Negation option
- all = self.listmessages()
- # Observed behavior: test for empty folder is done first
- if not all:
- raise Error, "no messages in %s" % self.name
- # Common case first: all is frequently the default
- if seq == 'all':
- return all
- # Test for X:Y before X-Y because 'seq:-n' matches both
- i = string.find(seq, ':')
- if i >= 0:
- head, dir, tail = seq[:i], '', seq[i+1:]
- if tail[:1] in '-+':
- dir, tail = tail[:1], tail[1:]
- if not isnumeric(tail):
- raise Error, "bad message list %s" % seq
- try:
- count = string.atoi(tail)
- except (ValueError, OverflowError):
- # Can't use sys.maxint because of i+count below
- count = len(all)
- try:
- anchor = self._parseindex(head, all)
- except Error, msg:
- seqs = self.getsequences()
- if not seqs.has_key(head):
- if not msg:
- msg = "bad message list %s" % seq
- raise Error, msg, sys.exc_info()[2]
- msgs = seqs[head]
- if not msgs:
- raise Error, "sequence %s empty" % head
- if dir == '-':
- return msgs[-count:]
- else:
- return msgs[:count]
- else:
- if not dir:
- if head in ('prev', 'last'):
- dir = '-'
- if dir == '-':
- i = bisect(all, anchor)
- return all[max(0, i-count):i]
- else:
- i = bisect(all, anchor-1)
- return all[i:i+count]
- # Test for X-Y next
- i = string.find(seq, '-')
- if i >= 0:
- begin = self._parseindex(seq[:i], all)
- end = self._parseindex(seq[i+1:], all)
- i = bisect(all, begin-1)
- j = bisect(all, end)
- r = all[i:j]
- if not r:
- raise Error, "bad message list %s" % seq
- return r
- # Neither X:Y nor X-Y; must be a number or a (pseudo-)sequence
- try:
- n = self._parseindex(seq, all)
- except Error, msg:
- seqs = self.getsequences()
- if not seqs.has_key(seq):
- if not msg:
- msg = "bad message list %s" % seq
- raise Error, msg
- return seqs[seq]
- else:
- if n not in all:
- if isnumeric(seq):
- raise Error, "message %d doesn't exist" % n
- else:
- raise Error, "no %s message" % seq
- else:
- return [n]
+ # XXX Still not complete (see mh-format(5)).
+ # Missing are:
+ # - 'prev', 'next' as count
+ # - Sequence-Negation option
+ all = self.listmessages()
+ # Observed behavior: test for empty folder is done first
+ if not all:
+ raise Error, "no messages in %s" % self.name
+ # Common case first: all is frequently the default
+ if seq == 'all':
+ return all
+ # Test for X:Y before X-Y because 'seq:-n' matches both
+ i = string.find(seq, ':')
+ if i >= 0:
+ head, dir, tail = seq[:i], '', seq[i+1:]
+ if tail[:1] in '-+':
+ dir, tail = tail[:1], tail[1:]
+ if not isnumeric(tail):
+ raise Error, "bad message list %s" % seq
+ try:
+ count = string.atoi(tail)
+ except (ValueError, OverflowError):
+ # Can't use sys.maxint because of i+count below
+ count = len(all)
+ try:
+ anchor = self._parseindex(head, all)
+ except Error, msg:
+ seqs = self.getsequences()
+ if not seqs.has_key(head):
+ if not msg:
+ msg = "bad message list %s" % seq
+ raise Error, msg, sys.exc_info()[2]
+ msgs = seqs[head]
+ if not msgs:
+ raise Error, "sequence %s empty" % head
+ if dir == '-':
+ return msgs[-count:]
+ else:
+ return msgs[:count]
+ else:
+ if not dir:
+ if head in ('prev', 'last'):
+ dir = '-'
+ if dir == '-':
+ i = bisect(all, anchor)
+ return all[max(0, i-count):i]
+ else:
+ i = bisect(all, anchor-1)
+ return all[i:i+count]
+ # Test for X-Y next
+ i = string.find(seq, '-')
+ if i >= 0:
+ begin = self._parseindex(seq[:i], all)
+ end = self._parseindex(seq[i+1:], all)
+ i = bisect(all, begin-1)
+ j = bisect(all, end)
+ r = all[i:j]
+ if not r:
+ raise Error, "bad message list %s" % seq
+ return r
+ # Neither X:Y nor X-Y; must be a number or a (pseudo-)sequence
+ try:
+ n = self._parseindex(seq, all)
+ except Error, msg:
+ seqs = self.getsequences()
+ if not seqs.has_key(seq):
+ if not msg:
+ msg = "bad message list %s" % seq
+ raise Error, msg
+ return seqs[seq]
+ else:
+ if n not in all:
+ if isnumeric(seq):
+ raise Error, "message %d doesn't exist" % n
+ else:
+ raise Error, "no %s message" % seq
+ else:
+ return [n]
# Internal: parse a message number (or cur, first, etc.)
def _parseindex(self, seq, all):
- if isnumeric(seq):
- try:
- return string.atoi(seq)
- except (OverflowError, ValueError):
- return sys.maxint
- if seq in ('cur', '.'):
- return self.getcurrent()
- if seq == 'first':
- return all[0]
- if seq == 'last':
- return all[-1]
- if seq == 'next':
- n = self.getcurrent()
- i = bisect(all, n)
- try:
- return all[i]
- except IndexError:
- raise Error, "no next message"
- if seq == 'prev':
- n = self.getcurrent()
- i = bisect(all, n-1)
- if i == 0:
- raise Error, "no prev message"
- try:
- return all[i-1]
- except IndexError:
- raise Error, "no prev message"
- raise Error, None
+ if isnumeric(seq):
+ try:
+ return string.atoi(seq)
+ except (OverflowError, ValueError):
+ return sys.maxint
+ if seq in ('cur', '.'):
+ return self.getcurrent()
+ if seq == 'first':
+ return all[0]
+ if seq == 'last':
+ return all[-1]
+ if seq == 'next':
+ n = self.getcurrent()
+ i = bisect(all, n)
+ try:
+ return all[i]
+ except IndexError:
+ raise Error, "no next message"
+ if seq == 'prev':
+ n = self.getcurrent()
+ i = bisect(all, n-1)
+ if i == 0:
+ raise Error, "no prev message"
+ try:
+ return all[i-1]
+ except IndexError:
+ raise Error, "no prev message"
+ raise Error, None
# Open a message -- returns a Message object
def openmessage(self, n):
- return Message(self, n)
+ return Message(self, n)
# Remove one or more messages -- may raise os.error
def removemessages(self, list):
- errors = []
- deleted = []
- for n in list:
- path = self.getmessagefilename(n)
- commapath = self.getmessagefilename(',' + str(n))
- try:
- os.unlink(commapath)
- except os.error:
- pass
- try:
- os.rename(path, commapath)
- except os.error, msg:
- errors.append(msg)
- else:
- deleted.append(n)
- if deleted:
- self.removefromallsequences(deleted)
- if errors:
- if len(errors) == 1:
- raise os.error, errors[0]
- else:
- raise os.error, ('multiple errors:', errors)
+ errors = []
+ deleted = []
+ for n in list:
+ path = self.getmessagefilename(n)
+ commapath = self.getmessagefilename(',' + str(n))
+ try:
+ os.unlink(commapath)
+ except os.error:
+ pass
+ try:
+ os.rename(path, commapath)
+ except os.error, msg:
+ errors.append(msg)
+ else:
+ deleted.append(n)
+ if deleted:
+ self.removefromallsequences(deleted)
+ if errors:
+ if len(errors) == 1:
+ raise os.error, errors[0]
+ else:
+ raise os.error, ('multiple errors:', errors)
# Refile one or more messages -- may raise os.error.
# 'tofolder' is an open folder object
def refilemessages(self, list, tofolder, keepsequences=0):
- errors = []
- refiled = {}
- for n in list:
- ton = tofolder.getlast() + 1
- path = self.getmessagefilename(n)
- topath = tofolder.getmessagefilename(ton)
- try:
- os.rename(path, topath)
- except os.error:
- # Try copying
- try:
- shutil.copy2(path, topath)
- os.unlink(path)
- except (IOError, os.error), msg:
- errors.append(msg)
- try:
- os.unlink(topath)
- except os.error:
- pass
- continue
- tofolder.setlast(ton)
- refiled[n] = ton
- if refiled:
- if keepsequences:
- tofolder._copysequences(self, refiled.items())
- self.removefromallsequences(refiled.keys())
- if errors:
- if len(errors) == 1:
- raise os.error, errors[0]
- else:
- raise os.error, ('multiple errors:', errors)
+ errors = []
+ refiled = {}
+ for n in list:
+ ton = tofolder.getlast() + 1
+ path = self.getmessagefilename(n)
+ topath = tofolder.getmessagefilename(ton)
+ try:
+ os.rename(path, topath)
+ except os.error:
+ # Try copying
+ try:
+ shutil.copy2(path, topath)
+ os.unlink(path)
+ except (IOError, os.error), msg:
+ errors.append(msg)
+ try:
+ os.unlink(topath)
+ except os.error:
+ pass
+ continue
+ tofolder.setlast(ton)
+ refiled[n] = ton
+ if refiled:
+ if keepsequences:
+ tofolder._copysequences(self, refiled.items())
+ self.removefromallsequences(refiled.keys())
+ if errors:
+ if len(errors) == 1:
+ raise os.error, errors[0]
+ else:
+ raise os.error, ('multiple errors:', errors)
# Helper for refilemessages() to copy sequences
def _copysequences(self, fromfolder, refileditems):
- fromsequences = fromfolder.getsequences()
- tosequences = self.getsequences()
- changed = 0
- for name, seq in fromsequences.items():
- try:
- toseq = tosequences[name]
- new = 0
- except:
- toseq = []
- new = 1
- for fromn, ton in refileditems:
- if fromn in seq:
- toseq.append(ton)
- changed = 1
- if new and toseq:
- tosequences[name] = toseq
- if changed:
- self.putsequences(tosequences)
+ fromsequences = fromfolder.getsequences()
+ tosequences = self.getsequences()
+ changed = 0
+ for name, seq in fromsequences.items():
+ try:
+ toseq = tosequences[name]
+ new = 0
+ except:
+ toseq = []
+ new = 1
+ for fromn, ton in refileditems:
+ if fromn in seq:
+ toseq.append(ton)
+ changed = 1
+ if new and toseq:
+ tosequences[name] = toseq
+ if changed:
+ self.putsequences(tosequences)
# Move one message over a specific destination message,
# which may or may not already exist.
def movemessage(self, n, tofolder, ton):
- path = self.getmessagefilename(n)
- # Open it to check that it exists
- f = open(path)
- f.close()
- del f
- topath = tofolder.getmessagefilename(ton)
- backuptopath = tofolder.getmessagefilename(',%d' % ton)
- try:
- os.rename(topath, backuptopath)
- except os.error:
- pass
- try:
- os.rename(path, topath)
- except os.error:
- # Try copying
- ok = 0
- try:
- tofolder.setlast(None)
- shutil.copy2(path, topath)
- ok = 1
- finally:
- if not ok:
- try:
- os.unlink(topath)
- except os.error:
- pass
- os.unlink(path)
- self.removefromallsequences([n])
+ path = self.getmessagefilename(n)
+ # Open it to check that it exists
+ f = open(path)
+ f.close()
+ del f
+ topath = tofolder.getmessagefilename(ton)
+ backuptopath = tofolder.getmessagefilename(',%d' % ton)
+ try:
+ os.rename(topath, backuptopath)
+ except os.error:
+ pass
+ try:
+ os.rename(path, topath)
+ except os.error:
+ # Try copying
+ ok = 0
+ try:
+ tofolder.setlast(None)
+ shutil.copy2(path, topath)
+ ok = 1
+ finally:
+ if not ok:
+ try:
+ os.unlink(topath)
+ except os.error:
+ pass
+ os.unlink(path)
+ self.removefromallsequences([n])
# Copy one message over a specific destination message,
# which may or may not already exist.
def copymessage(self, n, tofolder, ton):
- path = self.getmessagefilename(n)
- # Open it to check that it exists
- f = open(path)
- f.close()
- del f
- topath = tofolder.getmessagefilename(ton)
- backuptopath = tofolder.getmessagefilename(',%d' % ton)
- try:
- os.rename(topath, backuptopath)
- except os.error:
- pass
- ok = 0
- try:
- tofolder.setlast(None)
- shutil.copy2(path, topath)
- ok = 1
- finally:
- if not ok:
- try:
- os.unlink(topath)
- except os.error:
- pass
+ path = self.getmessagefilename(n)
+ # Open it to check that it exists
+ f = open(path)
+ f.close()
+ del f
+ topath = tofolder.getmessagefilename(ton)
+ backuptopath = tofolder.getmessagefilename(',%d' % ton)
+ try:
+ os.rename(topath, backuptopath)
+ except os.error:
+ pass
+ ok = 0
+ try:
+ tofolder.setlast(None)
+ shutil.copy2(path, topath)
+ ok = 1
+ finally:
+ if not ok:
+ try:
+ os.unlink(topath)
+ except os.error:
+ pass
# Create a message, with text from the open file txt.
def createmessage(self, n, txt):
- path = self.getmessagefilename(n)
- backuppath = self.getmessagefilename(',%d' % n)
- try:
- os.rename(path, backuppath)
- except os.error:
- pass
- ok = 0
- BUFSIZE = 16*1024
- try:
- f = open(path, "w")
- while 1:
- buf = txt.read(BUFSIZE)
- if not buf:
- break
- f.write(buf)
- f.close()
- ok = 1
- finally:
- if not ok:
- try:
- os.unlink(path)
- except os.error:
- pass
+ path = self.getmessagefilename(n)
+ backuppath = self.getmessagefilename(',%d' % n)
+ try:
+ os.rename(path, backuppath)
+ except os.error:
+ pass
+ ok = 0
+ BUFSIZE = 16*1024
+ try:
+ f = open(path, "w")
+ while 1:
+ buf = txt.read(BUFSIZE)
+ if not buf:
+ break
+ f.write(buf)
+ f.close()
+ ok = 1
+ finally:
+ if not ok:
+ try:
+ os.unlink(path)
+ except os.error:
+ pass
# Remove one or more messages from all sequeuces (including last)
# -- but not from 'cur'!!!
def removefromallsequences(self, list):
- if hasattr(self, 'last') and self.last in list:
- del self.last
- sequences = self.getsequences()
- changed = 0
- for name, seq in sequences.items():
- if name == 'cur':
- continue
- for n in list:
- if n in seq:
- seq.remove(n)
- changed = 1
- if not seq:
- del sequences[name]
- if changed:
- self.putsequences(sequences)
+ if hasattr(self, 'last') and self.last in list:
+ del self.last
+ sequences = self.getsequences()
+ changed = 0
+ for name, seq in sequences.items():
+ if name == 'cur':
+ continue
+ for n in list:
+ if n in seq:
+ seq.remove(n)
+ changed = 1
+ if not seq:
+ del sequences[name]
+ if changed:
+ self.putsequences(sequences)
# Return the last message number
def getlast(self):
- if not hasattr(self, 'last'):
- messages = self.listmessages()
- return self.last
+ if not hasattr(self, 'last'):
+ messages = self.listmessages()
+ return self.last
# Set the last message number
def setlast(self, last):
- if last is None:
- if hasattr(self, 'last'):
- del self.last
- else:
- self.last = last
+ if last is None:
+ if hasattr(self, 'last'):
+ del self.last
+ else:
+ self.last = last
class Message(mimetools.Message):
# Constructor
def __init__(self, f, n, fp = None):
- self.folder = f
- self.number = n
- if not fp:
- path = f.getmessagefilename(n)
- fp = open(path, 'r')
- mimetools.Message.__init__(self, fp)
+ self.folder = f
+ self.number = n
+ if not fp:
+ path = f.getmessagefilename(n)
+ fp = open(path, 'r')
+ mimetools.Message.__init__(self, fp)
# String representation
def __repr__(self):
- return 'Message(%s, %s)' % (repr(self.folder), self.number)
+ return 'Message(%s, %s)' % (repr(self.folder), self.number)
# Return the message's header text as a string. If an
# argument is specified, it is used as a filter predicate to
# decide which headers to return (its argument is the header
# name converted to lower case).
def getheadertext(self, pred = None):
- if not pred:
- return string.joinfields(self.headers, '')
- headers = []
- hit = 0
- for line in self.headers:
- if line[0] not in string.whitespace:
- i = string.find(line, ':')
- if i > 0:
- hit = pred(string.lower(line[:i]))
- if hit: headers.append(line)
- return string.joinfields(headers, '')
+ if not pred:
+ return string.joinfields(self.headers, '')
+ headers = []
+ hit = 0
+ for line in self.headers:
+ if line[0] not in string.whitespace:
+ i = string.find(line, ':')
+ if i > 0:
+ hit = pred(string.lower(line[:i]))
+ if hit: headers.append(line)
+ return string.joinfields(headers, '')
# Return the message's body text as string. This undoes a
# Content-Transfer-Encoding, but does not interpret other MIME
# features (e.g. multipart messages). To suppress to
# decoding, pass a 0 as argument
def getbodytext(self, decode = 1):
- self.fp.seek(self.startofbody)
- encoding = self.getencoding()
- if not decode or encoding in ('7bit', '8bit', 'binary'):
- return self.fp.read()
- from StringIO import StringIO
- output = StringIO()
- mimetools.decode(self.fp, output, encoding)
- return output.getvalue()
+ self.fp.seek(self.startofbody)
+ encoding = self.getencoding()
+ if not decode or encoding in ('7bit', '8bit', 'binary'):
+ return self.fp.read()
+ from StringIO import StringIO
+ output = StringIO()
+ mimetools.decode(self.fp, output, encoding)
+ return output.getvalue()
# Only for multipart messages: return the message's body as a
# list of SubMessage objects. Each submessage object behaves
# (almost) as a Message object.
def getbodyparts(self):
- if self.getmaintype() != 'multipart':
- raise Error, 'Content-Type is not multipart/*'
- bdry = self.getparam('boundary')
- if not bdry:
- raise Error, 'multipart/* without boundary param'
- self.fp.seek(self.startofbody)
- mf = multifile.MultiFile(self.fp)
- mf.push(bdry)
- parts = []
- while mf.next():
- n = str(self.number) + '.' + `1 + len(parts)`
- part = SubMessage(self.folder, n, mf)
- parts.append(part)
- mf.pop()
- return parts
+ if self.getmaintype() != 'multipart':
+ raise Error, 'Content-Type is not multipart/*'
+ bdry = self.getparam('boundary')
+ if not bdry:
+ raise Error, 'multipart/* without boundary param'
+ self.fp.seek(self.startofbody)
+ mf = multifile.MultiFile(self.fp)
+ mf.push(bdry)
+ parts = []
+ while mf.next():
+ n = str(self.number) + '.' + `1 + len(parts)`
+ part = SubMessage(self.folder, n, mf)
+ parts.append(part)
+ mf.pop()
+ return parts
# Return body, either a string or a list of messages
def getbody(self):
- if self.getmaintype() == 'multipart':
- return self.getbodyparts()
- else:
- return self.getbodytext()
+ if self.getmaintype() == 'multipart':
+ return self.getbodyparts()
+ else:
+ return self.getbodytext()
class SubMessage(Message):
# Constructor
def __init__(self, f, n, fp):
- Message.__init__(self, f, n, fp)
- if self.getmaintype() == 'multipart':
- self.body = Message.getbodyparts(self)
- else:
- self.body = Message.getbodytext(self)
- # XXX If this is big, should remember file pointers
+ Message.__init__(self, f, n, fp)
+ if self.getmaintype() == 'multipart':
+ self.body = Message.getbodyparts(self)
+ else:
+ self.body = Message.getbodytext(self)
+ # XXX If this is big, should remember file pointers
# String representation
def __repr__(self):
- f, n, fp = self.folder, self.number, self.fp
- return 'SubMessage(%s, %s, %s)' % (f, n, fp)
+ f, n, fp = self.folder, self.number, self.fp
+ return 'SubMessage(%s, %s, %s)' % (f, n, fp)
def getbodytext(self):
- if type(self.body) == type(''):
- return self.body
+ if type(self.body) == type(''):
+ return self.body
def getbodyparts(self):
- if type(self.body) == type([]):
- return self.body
+ if type(self.body) == type([]):
+ return self.body
def getbody(self):
- return self.body
+ return self.body
# Class implementing sets of integers.
class IntSet:
def __init__(self, data = None, sep = ',', rng = '-'):
- self.pairs = []
- self.sep = sep
- self.rng = rng
- if data: self.fromstring(data)
+ self.pairs = []
+ self.sep = sep
+ self.rng = rng
+ if data: self.fromstring(data)
def reset(self):
- self.pairs = []
+ self.pairs = []
def __cmp__(self, other):
- return cmp(self.pairs, other.pairs)
+ return cmp(self.pairs, other.pairs)
def __hash__(self):
- return hash(self.pairs)
+ return hash(self.pairs)
def __repr__(self):
- return 'IntSet(%s, %s, %s)' % (`self.tostring()`,
- `self.sep`, `self.rng`)
+ return 'IntSet(%s, %s, %s)' % (`self.tostring()`,
+ `self.sep`, `self.rng`)
def normalize(self):
- self.pairs.sort()
- i = 1
- while i < len(self.pairs):
- alo, ahi = self.pairs[i-1]
- blo, bhi = self.pairs[i]
- if ahi >= blo-1:
- self.pairs[i-1:i+1] = [(alo, max(ahi, bhi))]
- else:
- i = i+1
+ self.pairs.sort()
+ i = 1
+ while i < len(self.pairs):
+ alo, ahi = self.pairs[i-1]
+ blo, bhi = self.pairs[i]
+ if ahi >= blo-1:
+ self.pairs[i-1:i+1] = [(alo, max(ahi, bhi))]
+ else:
+ i = i+1
def tostring(self):
- s = ''
- for lo, hi in self.pairs:
- if lo == hi: t = `lo`
- else: t = `lo` + self.rng + `hi`
- if s: s = s + (self.sep + t)
- else: s = t
- return s
+ s = ''
+ for lo, hi in self.pairs:
+ if lo == hi: t = `lo`
+ else: t = `lo` + self.rng + `hi`
+ if s: s = s + (self.sep + t)
+ else: s = t
+ return s
def tolist(self):
- l = []
- for lo, hi in self.pairs:
- m = range(lo, hi+1)
- l = l + m
- return l
+ l = []
+ for lo, hi in self.pairs:
+ m = range(lo, hi+1)
+ l = l + m
+ return l
def fromlist(self, list):
- for i in list:
- self.append(i)
+ for i in list:
+ self.append(i)
def clone(self):
- new = IntSet()
- new.pairs = self.pairs[:]
- return new
+ new = IntSet()
+ new.pairs = self.pairs[:]
+ return new
def min(self):
- return self.pairs[0][0]
+ return self.pairs[0][0]
def max(self):
- return self.pairs[-1][-1]
+ return self.pairs[-1][-1]
def contains(self, x):
- for lo, hi in self.pairs:
- if lo <= x <= hi: return 1
- return 0
+ for lo, hi in self.pairs:
+ if lo <= x <= hi: return 1
+ return 0
def append(self, x):
- for i in range(len(self.pairs)):
- lo, hi = self.pairs[i]
- if x < lo: # Need to insert before
- if x+1 == lo:
- self.pairs[i] = (x, hi)
- else:
- self.pairs.insert(i, (x, x))
- if i > 0 and x-1 == self.pairs[i-1][1]:
- # Merge with previous
- self.pairs[i-1:i+1] = [
- (self.pairs[i-1][0],
- self.pairs[i][1])
- ]
- return
- if x <= hi: # Already in set
- return
- i = len(self.pairs) - 1
- if i >= 0:
- lo, hi = self.pairs[i]
- if x-1 == hi:
- self.pairs[i] = lo, x
- return
- self.pairs.append((x, x))
+ for i in range(len(self.pairs)):
+ lo, hi = self.pairs[i]
+ if x < lo: # Need to insert before
+ if x+1 == lo:
+ self.pairs[i] = (x, hi)
+ else:
+ self.pairs.insert(i, (x, x))
+ if i > 0 and x-1 == self.pairs[i-1][1]:
+ # Merge with previous
+ self.pairs[i-1:i+1] = [
+ (self.pairs[i-1][0],
+ self.pairs[i][1])
+ ]
+ return
+ if x <= hi: # Already in set
+ return
+ i = len(self.pairs) - 1
+ if i >= 0:
+ lo, hi = self.pairs[i]
+ if x-1 == hi:
+ self.pairs[i] = lo, x
+ return
+ self.pairs.append((x, x))
def addpair(self, xlo, xhi):
- if xlo > xhi: return
- self.pairs.append((xlo, xhi))
- self.normalize()
+ if xlo > xhi: return
+ self.pairs.append((xlo, xhi))
+ self.normalize()
def fromstring(self, data):
- import string
- new = []
- for part in string.splitfields(data, self.sep):
- list = []
- for subp in string.splitfields(part, self.rng):
- s = string.strip(subp)
- list.append(string.atoi(s))
- if len(list) == 1:
- new.append((list[0], list[0]))
- elif len(list) == 2 and list[0] <= list[1]:
- new.append((list[0], list[1]))
- else:
- raise ValueError, 'bad data passed to IntSet'
- self.pairs = self.pairs + new
- self.normalize()
+ import string
+ new = []
+ for part in string.splitfields(data, self.sep):
+ list = []
+ for subp in string.splitfields(part, self.rng):
+ s = string.strip(subp)
+ list.append(string.atoi(s))
+ if len(list) == 1:
+ new.append((list[0], list[0]))
+ elif len(list) == 2 and list[0] <= list[1]:
+ new.append((list[0], list[1]))
+ else:
+ raise ValueError, 'bad data passed to IntSet'
+ self.pairs = self.pairs + new
+ self.normalize()
# Subroutines to read/write entries in .mh_profile and .mh_sequences
def pickline(file, key, casefold = 1):
try:
- f = open(file, 'r')
+ f = open(file, 'r')
except IOError:
- return None
+ return None
pat = re.escape(key) + ':'
prog = re.compile(pat, casefold and re.IGNORECASE)
while 1:
- line = f.readline()
- if not line: break
- if prog.match(line):
- text = line[len(key)+1:]
- while 1:
- line = f.readline()
- if not line or line[0] not in string.whitespace:
- break
- text = text + line
- return string.strip(text)
+ line = f.readline()
+ if not line: break
+ if prog.match(line):
+ text = line[len(key)+1:]
+ while 1:
+ line = f.readline()
+ if not line or line[0] not in string.whitespace:
+ break
+ text = text + line
+ return string.strip(text)
return None
def updateline(file, key, value, casefold = 1):
try:
- f = open(file, 'r')
- lines = f.readlines()
- f.close()
+ f = open(file, 'r')
+ lines = f.readlines()
+ f.close()
except IOError:
- lines = []
+ lines = []
pat = re.escape(key) + ':(.*)\n'
prog = re.compile(pat, casefold and re.IGNORECASE)
if value is None:
- newline = None
+ newline = None
else:
- newline = '%s: %s\n' % (key, value)
+ newline = '%s: %s\n' % (key, value)
for i in range(len(lines)):
- line = lines[i]
- if prog.match(line):
- if newline is None:
- del lines[i]
- else:
- lines[i] = newline
- break
+ line = lines[i]
+ if prog.match(line):
+ if newline is None:
+ del lines[i]
+ else:
+ lines[i] = newline
+ break
else:
- if newline is not None:
- lines.append(newline)
+ if newline is not None:
+ lines.append(newline)
tempfile = file + "~"
f = open(tempfile, 'w')
for line in lines:
- f.write(line)
+ f.write(line)
f.close()
os.rename(tempfile, file)
do('mh.listfolders()')
do('mh.listallfolders()')
testfolders = ['@test', '@test/test1', '@test/test2',
- '@test/test1/test11', '@test/test1/test12',
- '@test/test1/test11/test111']
+ '@test/test1/test11', '@test/test1/test12',
+ '@test/test1/test11/test111']
for t in testfolders: do('mh.makefolder(%s)' % `t`)
do('mh.listsubfolders(\'@test\')')
do('mh.listallsubfolders(\'@test\')')
f = mh.openfolder(context)
do('f.getcurrent()')
for seq in ['first', 'last', 'cur', '.', 'prev', 'next',
- 'first:3', 'last:3', 'cur:3', 'cur:-3',
- 'prev:3', 'next:3',
- '1:3', '1:-3', '100:3', '100:-3', '10000:3', '10000:-3',
- 'all']:
- try:
- do('f.parsesequence(%s)' % `seq`)
- except Error, msg:
- print "Error:", msg
- stuff = os.popen("pick %s 2>/dev/null" % `seq`).read()
- list = map(string.atoi, string.split(stuff))
- print list, "<-- pick"
+ 'first:3', 'last:3', 'cur:3', 'cur:-3',
+ 'prev:3', 'next:3',
+ '1:3', '1:-3', '100:3', '100:-3', '10000:3', '10000:-3',
+ 'all']:
+ try:
+ do('f.parsesequence(%s)' % `seq`)
+ except Error, msg:
+ print "Error:", msg
+ stuff = os.popen("pick %s 2>/dev/null" % `seq`).read()
+ list = map(string.atoi, string.split(stuff))
+ print list, "<-- pick"
do('f.listmessages()')
"""
if not inited:
- init()
+ init()
base, ext = posixpath.splitext(url)
while suffix_map.has_key(ext):
- base, ext = posixpath.splitext(base + suffix_map[ext])
+ base, ext = posixpath.splitext(base + suffix_map[ext])
if encodings_map.has_key(ext):
- encoding = encodings_map[ext]
- base, ext = posixpath.splitext(base)
+ encoding = encodings_map[ext]
+ base, ext = posixpath.splitext(base)
else:
- encoding = None
+ encoding = None
if types_map.has_key(ext):
- return types_map[ext], encoding
+ return types_map[ext], encoding
elif types_map.has_key(string.lower(ext)):
- return types_map[string.lower(ext)], encoding
+ return types_map[string.lower(ext)], encoding
else:
- return None, encoding
+ return None, encoding
def init(files=None):
global inited
for file in files or knownfiles:
- s = read_mime_types(file)
- if s:
- for key, value in s.items():
- types_map[key] = value
+ s = read_mime_types(file)
+ if s:
+ for key, value in s.items():
+ types_map[key] = value
inited = 1
def read_mime_types(file):
try:
- f = open(file)
+ f = open(file)
except IOError:
- return None
+ return None
map = {}
while 1:
- line = f.readline()
- if not line: break
- words = string.split(line)
- for i in range(len(words)):
- if words[i][0] == '#':
- del words[i:]
- break
- if not words: continue
- type, suffixes = words[0], words[1:]
- for suff in suffixes:
- map['.'+suff] = type
+ line = f.readline()
+ if not line: break
+ words = string.split(line)
+ for i in range(len(words)):
+ if words[i][0] == '#':
+ del words[i:]
+ break
+ if not words: continue
+ type, suffixes = words[0], words[1:]
+ for suff in suffixes:
+ map['.'+suff] = type
f.close()
return map
self.write(STOP)
def dump_special(self, callable, args, state = None):
- if type(args) is not TupleType and args is not None:
+ if type(args) is not TupleType and args is not None:
raise PicklingError, "Second argument to dump_special " \
"must be a tuple"
memo = self.memo
if (not pers_save):
- pid = self.persistent_id(object)
- if (pid is not None):
+ pid = self.persistent_id(object)
+ if (pid is not None):
self.save_pers(pid)
return
t = type(object)
- if ((t is TupleType) and (len(object) == 0)):
- if (self.bin):
+ if ((t is TupleType) and (len(object) == 0)):
+ if (self.bin):
self.save_empty_tuple(object)
else:
self.save_tuple(object)
else:
tup = reduce(object)
- if type(tup) is StringType:
- self.save_global(object, tup)
- return
+ if type(tup) is StringType:
+ self.save_global(object, tup)
+ return
if (type(tup) is not TupleType):
raise PicklingError, "Value returned by %s must be a " \
l = len(tup)
- if ((l != 2) and (l != 3)):
+ if ((l != 2) and (l != 3)):
raise PicklingError, "tuple returned by %s must contain " \
"only two or three elements" % reduce
"by %s must be a tuple" % reduce
self.save_reduce(callable, arg_tup, state)
- memo_len = len(memo)
- self.write(self.put(memo_len))
- memo[d] = (memo_len, object)
+ memo_len = len(memo)
+ self.write(self.put(memo_len))
+ memo[d] = (memo_len, object)
return
f(self, object)
save(arg_tup)
write(REDUCE)
- if (state is not None):
+ if (state is not None):
save(state)
write(BUILD)
save(element)
if (len(object) and memo.has_key(d)):
- if (self.bin):
+ if (self.bin):
write(POP_MARK + self.get(memo[d][0]))
return
save = self.save
memo = self.memo
- if (self.bin):
+ if (self.bin):
write(EMPTY_LIST)
else:
write(MARK + LIST)
save = self.save
memo = self.memo
- if (self.bin):
+ if (self.bin):
write(EMPTY_DICT)
else:
write(MARK + DICT)
if hasattr(object, '__getinitargs__'):
args = object.__getinitargs__()
len(args) # XXX Assert it's a sequence
- _keep_alive(args, memo)
+ _keep_alive(args, memo)
else:
args = ()
stuff = object.__dict__
else:
stuff = getstate()
- _keep_alive(stuff, memo)
+ _keep_alive(stuff, memo)
save(stuff)
write(BUILD)
dispatch[InstanceType] = save_inst
if (name is None):
name = object.__name__
- try:
- module = object.__module__
- except AttributeError:
- module = whichmodule(object, name)
+ try:
+ module = object.__module__
+ except AttributeError:
+ module = whichmodule(object, name)
memo_len = len(memo)
write(GLOBAL + module + '\n' + name + '\n' +
the memo itself...
"""
try:
- memo[id(memo)].append(x)
+ memo[id(memo)].append(x)
except KeyError:
- # aha, this is the first one :-)
- memo[id(memo)]=[x]
+ # aha, this is the first one :-)
+ memo[id(memo)]=[x]
classmap = {}
import sys
for name, module in sys.modules.items():
- if name != '__main__' and \
- hasattr(module, clsname) and \
+ if name != '__main__' and \
+ hasattr(module, clsname) and \
getattr(module, clsname) is cls:
break
else:
module = self.readline()[:-1]
name = self.readline()[:-1]
klass = self.find_class(module, name)
- instantiated = 0
- if (not args and type(klass) is ClassType and
- not hasattr(klass, "__getinitargs__")):
- try:
- value = _EmptyClass()
- value.__class__ = klass
- except RuntimeError:
- # In restricted execution, assignment to inst.__class__ is
- # prohibited
- pass
- if not instantiated:
- value = apply(klass, args)
+ instantiated = 0
+ if (not args and type(klass) is ClassType and
+ not hasattr(klass, "__getinitargs__")):
+ try:
+ value = _EmptyClass()
+ value.__class__ = klass
+ except RuntimeError:
+ # In restricted execution, assignment to inst.__class__ is
+ # prohibited
+ pass
+ if not instantiated:
+ value = apply(klass, args)
self.append(value)
dispatch[INST] = load_inst
del stack[k + 1]
args = tuple(stack[k + 1:])
del stack[k:]
- instantiated = 0
- if (not args and type(klass) is ClassType and
- not hasattr(klass, "__getinitargs__")):
- try:
- value = _EmptyClass()
- value.__class__ = klass
- instantiated = 1
- except RuntimeError:
- # In restricted execution, assignment to inst.__class__ is
- # prohibited
- pass
- if not instantiated:
- value = apply(klass, args)
+ instantiated = 0
+ if (not args and type(klass) is ClassType and
+ not hasattr(klass, "__getinitargs__")):
+ try:
+ value = _EmptyClass()
+ value.__class__ = klass
+ instantiated = 1
+ except RuntimeError:
+ # In restricted execution, assignment to inst.__class__ is
+ # prohibited
+ pass
+ if not instantiated:
+ value = apply(klass, args)
self.append(value)
dispatch[OBJ] = load_obj
callable = stack[-2]
arg_tup = stack[-1]
- del stack[-2:]
+ del stack[-2:]
- if type(callable) is not ClassType:
- if not safe_constructors.has_key(callable):
- try:
+ if type(callable) is not ClassType:
+ if not safe_constructors.has_key(callable):
+ try:
safe = callable.__safe_for_unpickling__
except AttributeError:
safe = None
raise UnpicklingError, "%s is not safe for " \
"unpickling" % callable
- if arg_tup is None:
- value = callable.__basicnew__()
- else:
- value = apply(callable, arg_tup)
+ if arg_tup is None:
+ value = callable.__basicnew__()
+ else:
+ value = apply(callable, arg_tup)
self.append(value)
dispatch[REDUCE] = load_reduce
def load_pop_mark(self):
k = self.marker()
- del self.stack[k:]
+ del self.stack[k:]
dispatch[POP_MARK] = load_pop_mark
def load_dup(self):
stack = self.stack
mark = self.marker()
list = stack[mark - 1]
- for i in range(mark + 1, len(stack)):
+ for i in range(mark + 1, len(stack)):
list.append(stack[i])
del stack[mark:]
stack = self.stack
mark = self.marker()
dict = stack[mark - 1]
- for i in range(mark + 1, len(stack), 2):
+ for i in range(mark + 1, len(stack), 2):
dict[stack[i]] = stack[i + 1]
del stack[mark:]
try:
setstate = inst.__setstate__
except AttributeError:
- try:
- inst.__dict__.update(value)
- except RuntimeError:
- # XXX In restricted execution, the instance's __dict__ is not
- # accessible. Use the old way of unpickling the instance
- # variables. This is a semantic different when unpickling in
- # restricted vs. unrestricted modes.
- for k, v in value.items():
- setattr(inst, k, v)
+ try:
+ inst.__dict__.update(value)
+ except RuntimeError:
+ # XXX In restricted execution, the instance's __dict__ is not
+ # accessible. Use the old way of unpickling the instance
+ # variables. This is a semantic different when unpickling in
+ # restricted vs. unrestricted modes.
+ for k, v in value.items():
+ setattr(inst, k, v)
else:
setstate(value)
dispatch[BUILD] = load_build
import sys
import string
-MAXFD = 256 # Max number of file descriptors (os.getdtablesize()???)
+MAXFD = 256 # Max number of file descriptors (os.getdtablesize()???)
_active = []
def _cleanup():
for inst in _active[:]:
- inst.poll()
+ inst.poll()
class Popen3:
def __init__(self, cmd, capturestderr=0, bufsize=-1):
- if type(cmd) == type(''):
- cmd = ['/bin/sh', '-c', cmd]
- p2cread, p2cwrite = os.pipe()
- c2pread, c2pwrite = os.pipe()
- if capturestderr:
- errout, errin = os.pipe()
- self.pid = os.fork()
- if self.pid == 0:
- # Child
- os.close(0)
- os.close(1)
- if os.dup(p2cread) <> 0:
- sys.stderr.write('popen2: bad read dup\n')
- if os.dup(c2pwrite) <> 1:
- sys.stderr.write('popen2: bad write dup\n')
- if capturestderr:
- os.close(2)
- if os.dup(errin) <> 2: pass
- for i in range(3, MAXFD):
- try:
- os.close(i)
- except: pass
- try:
- os.execvp(cmd[0], cmd)
- finally:
- os._exit(1)
- # Shouldn't come here, I guess
- os._exit(1)
- os.close(p2cread)
- self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
- os.close(c2pwrite)
- self.fromchild = os.fdopen(c2pread, 'r', bufsize)
- if capturestderr:
- os.close(errin)
- self.childerr = os.fdopen(errout, 'r', bufsize)
- else:
- self.childerr = None
- self.sts = -1 # Child not completed yet
- _active.append(self)
+ if type(cmd) == type(''):
+ cmd = ['/bin/sh', '-c', cmd]
+ p2cread, p2cwrite = os.pipe()
+ c2pread, c2pwrite = os.pipe()
+ if capturestderr:
+ errout, errin = os.pipe()
+ self.pid = os.fork()
+ if self.pid == 0:
+ # Child
+ os.close(0)
+ os.close(1)
+ if os.dup(p2cread) <> 0:
+ sys.stderr.write('popen2: bad read dup\n')
+ if os.dup(c2pwrite) <> 1:
+ sys.stderr.write('popen2: bad write dup\n')
+ if capturestderr:
+ os.close(2)
+ if os.dup(errin) <> 2: pass
+ for i in range(3, MAXFD):
+ try:
+ os.close(i)
+ except: pass
+ try:
+ os.execvp(cmd[0], cmd)
+ finally:
+ os._exit(1)
+ # Shouldn't come here, I guess
+ os._exit(1)
+ os.close(p2cread)
+ self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
+ os.close(c2pwrite)
+ self.fromchild = os.fdopen(c2pread, 'r', bufsize)
+ if capturestderr:
+ os.close(errin)
+ self.childerr = os.fdopen(errout, 'r', bufsize)
+ else:
+ self.childerr = None
+ self.sts = -1 # Child not completed yet
+ _active.append(self)
def poll(self):
- if self.sts < 0:
- try:
- pid, sts = os.waitpid(self.pid, os.WNOHANG)
- if pid == self.pid:
- self.sts = sts
- _active.remove(self)
- except os.error:
- pass
- return self.sts
+ if self.sts < 0:
+ try:
+ pid, sts = os.waitpid(self.pid, os.WNOHANG)
+ if pid == self.pid:
+ self.sts = sts
+ _active.remove(self)
+ except os.error:
+ pass
+ return self.sts
def wait(self):
- pid, sts = os.waitpid(self.pid, 0)
- if pid == self.pid:
- self.sts = sts
- _active.remove(self)
- return self.sts
+ pid, sts = os.waitpid(self.pid, 0)
+ if pid == self.pid:
+ self.sts = sts
+ _active.remove(self)
+ return self.sts
def popen2(cmd, bufsize=-1):
_cleanup()
# Extended file operations
#
# f = posixfile.open(filename, [mode, [bufsize]])
-# will create a new posixfile object
+# will create a new posixfile object
#
# f = posixfile.fileopen(fileobject)
-# will create a posixfile object from a builtin file object
+# will create a posixfile object from a builtin file object
#
# f.file()
-# will return the original builtin file object
+# will return the original builtin file object
#
# f.dup()
-# will return a new file object based on a new filedescriptor
+# will return a new file object based on a new filedescriptor
#
# f.dup2(fd)
-# will return a new file object based on the given filedescriptor
+# will return a new file object based on the given filedescriptor
#
# f.flags(mode)
-# will turn on the associated flag (merge)
-# mode can contain the following characters:
+# will turn on the associated flag (merge)
+# mode can contain the following characters:
#
# (character representing a flag)
-# a append only flag
-# c close on exec flag
-# n no delay flag
-# s synchronization flag
+# a append only flag
+# c close on exec flag
+# n no delay flag
+# s synchronization flag
# (modifiers)
-# ! turn flags 'off' instead of default 'on'
-# = copy flags 'as is' instead of default 'merge'
-# ? return a string in which the characters represent the flags
-# that are set
+# ! turn flags 'off' instead of default 'on'
+# = copy flags 'as is' instead of default 'merge'
+# ? return a string in which the characters represent the flags
+# that are set
#
-# note: - the '!' and '=' modifiers are mutually exclusive.
-# - the '?' modifier will return the status of the flags after they
-# have been changed by other characters in the mode string
+# note: - the '!' and '=' modifiers are mutually exclusive.
+# - the '?' modifier will return the status of the flags after they
+# have been changed by other characters in the mode string
#
# f.lock(mode [, len [, start [, whence]]])
-# will (un)lock a region
-# mode can contain the following characters:
+# will (un)lock a region
+# mode can contain the following characters:
#
# (character representing type of lock)
-# u unlock
-# r read lock
-# w write lock
+# u unlock
+# r read lock
+# w write lock
# (modifiers)
-# | wait until the lock can be granted
-# ? return the first lock conflicting with the requested lock
-# or 'None' if there is no conflict. The lock returned is in the
-# format (mode, len, start, whence, pid) where mode is a
-# character representing the type of lock ('r' or 'w')
+# | wait until the lock can be granted
+# ? return the first lock conflicting with the requested lock
+# or 'None' if there is no conflict. The lock returned is in the
+# format (mode, len, start, whence, pid) where mode is a
+# character representing the type of lock ('r' or 'w')
#
-# note: - the '?' modifier prevents a region from being locked; it is
-# query only
+# note: - the '?' modifier prevents a region from being locked; it is
+# query only
#
class _posixfile_:
# Internal routines
#
def __repr__(self):
- file = self._file_
- return "<%s posixfile '%s', mode '%s' at %s>" % \
- (self.states[file.closed], file.name, file.mode, \
- hex(id(self))[2:])
+ file = self._file_
+ return "<%s posixfile '%s', mode '%s' at %s>" % \
+ (self.states[file.closed], file.name, file.mode, \
+ hex(id(self))[2:])
def __del__(self):
- self._file_.close()
+ self._file_.close()
#
# Initialization routines
#
def open(self, name, mode='r', bufsize=-1):
- import __builtin__
- return self.fileopen(__builtin__.open(name, mode, bufsize))
+ import __builtin__
+ return self.fileopen(__builtin__.open(name, mode, bufsize))
def fileopen(self, file):
- if `type(file)` != "<type 'file'>":
- raise TypeError, 'posixfile.fileopen() arg must be file object'
- self._file_ = file
- # Copy basic file methods
- for method in file.__methods__:
- setattr(self, method, getattr(file, method))
- return self
+ if `type(file)` != "<type 'file'>":
+ raise TypeError, 'posixfile.fileopen() arg must be file object'
+ self._file_ = file
+ # Copy basic file methods
+ for method in file.__methods__:
+ setattr(self, method, getattr(file, method))
+ return self
#
# New methods
#
def file(self):
- return self._file_
+ return self._file_
def dup(self):
- import posix
+ import posix
- try: ignore = posix.fdopen
- except: raise AttributeError, 'dup() method unavailable'
+ try: ignore = posix.fdopen
+ except: raise AttributeError, 'dup() method unavailable'
- return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)
+ return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)
def dup2(self, fd):
- import posix
+ import posix
- try: ignore = posix.fdopen
- except: raise AttributeError, 'dup() method unavailable'
+ try: ignore = posix.fdopen
+ except: raise AttributeError, 'dup() method unavailable'
- posix.dup2(self._file_.fileno(), fd)
- return posix.fdopen(fd, self._file_.mode)
+ posix.dup2(self._file_.fileno(), fd)
+ return posix.fdopen(fd, self._file_.mode)
def flags(self, *which):
- import fcntl, FCNTL
-
- if which:
- if len(which) > 1:
- raise TypeError, 'Too many arguments'
- which = which[0]
- else: which = '?'
-
- l_flags = 0
- if 'n' in which: l_flags = l_flags | FCNTL.O_NDELAY
- if 'a' in which: l_flags = l_flags | FCNTL.O_APPEND
- if 's' in which: l_flags = l_flags | FCNTL.O_SYNC
-
- file = self._file_
-
- if '=' not in which:
- cur_fl = fcntl.fcntl(file.fileno(), FCNTL.F_GETFL, 0)
- if '!' in which: l_flags = cur_fl & ~ l_flags
- else: l_flags = cur_fl | l_flags
-
- l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFL, l_flags)
-
- if 'c' in which:
- arg = ('!' not in which) # 0 is don't, 1 is do close on exec
- l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFD, arg)
-
- if '?' in which:
- which = '' # Return current flags
- l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_GETFL, 0)
- if FCNTL.O_APPEND & l_flags: which = which + 'a'
- if fcntl.fcntl(file.fileno(), FCNTL.F_GETFD, 0) & 1:
- which = which + 'c'
- if FCNTL.O_NDELAY & l_flags: which = which + 'n'
- if FCNTL.O_SYNC & l_flags: which = which + 's'
- return which
-
+ import fcntl, FCNTL
+
+ if which:
+ if len(which) > 1:
+ raise TypeError, 'Too many arguments'
+ which = which[0]
+ else: which = '?'
+
+ l_flags = 0
+ if 'n' in which: l_flags = l_flags | FCNTL.O_NDELAY
+ if 'a' in which: l_flags = l_flags | FCNTL.O_APPEND
+ if 's' in which: l_flags = l_flags | FCNTL.O_SYNC
+
+ file = self._file_
+
+ if '=' not in which:
+ cur_fl = fcntl.fcntl(file.fileno(), FCNTL.F_GETFL, 0)
+ if '!' in which: l_flags = cur_fl & ~ l_flags
+ else: l_flags = cur_fl | l_flags
+
+ l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFL, l_flags)
+
+ if 'c' in which:
+ arg = ('!' not in which) # 0 is don't, 1 is do close on exec
+ l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFD, arg)
+
+ if '?' in which:
+ which = '' # Return current flags
+ l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_GETFL, 0)
+ if FCNTL.O_APPEND & l_flags: which = which + 'a'
+ if fcntl.fcntl(file.fileno(), FCNTL.F_GETFD, 0) & 1:
+ which = which + 'c'
+ if FCNTL.O_NDELAY & l_flags: which = which + 'n'
+ if FCNTL.O_SYNC & l_flags: which = which + 's'
+ return which
+
def lock(self, how, *args):
- import struct, fcntl, FCNTL
-
- if 'w' in how: l_type = FCNTL.F_WRLCK
- elif 'r' in how: l_type = FCNTL.F_RDLCK
- elif 'u' in how: l_type = FCNTL.F_UNLCK
- else: raise TypeError, 'no type of lock specified'
-
- if '|' in how: cmd = FCNTL.F_SETLKW
- elif '?' in how: cmd = FCNTL.F_GETLK
- else: cmd = FCNTL.F_SETLK
-
- l_whence = 0
- l_start = 0
- l_len = 0
-
- if len(args) == 1:
- l_len = args[0]
- elif len(args) == 2:
- l_len, l_start = args
- elif len(args) == 3:
- l_len, l_start, l_whence = args
- elif len(args) > 3:
- raise TypeError, 'too many arguments'
-
- # Hack by davem@magnet.com to get locking to go on freebsd;
- # additions for AIX by Vladimir.Marangozov@imag.fr
+ import struct, fcntl, FCNTL
+
+ if 'w' in how: l_type = FCNTL.F_WRLCK
+ elif 'r' in how: l_type = FCNTL.F_RDLCK
+ elif 'u' in how: l_type = FCNTL.F_UNLCK
+ else: raise TypeError, 'no type of lock specified'
+
+ if '|' in how: cmd = FCNTL.F_SETLKW
+ elif '?' in how: cmd = FCNTL.F_GETLK
+ else: cmd = FCNTL.F_SETLK
+
+ l_whence = 0
+ l_start = 0
+ l_len = 0
+
+ if len(args) == 1:
+ l_len = args[0]
+ elif len(args) == 2:
+ l_len, l_start = args
+ elif len(args) == 3:
+ l_len, l_start, l_whence = args
+ elif len(args) > 3:
+ raise TypeError, 'too many arguments'
+
+ # Hack by davem@magnet.com to get locking to go on freebsd;
+ # additions for AIX by Vladimir.Marangozov@imag.fr
import sys, os
if sys.platform in ('netbsd1', 'freebsd2', 'freebsd3'):
- flock = struct.pack('lxxxxlxxxxlhh', \
- l_start, l_len, os.getpid(), l_type, l_whence)
+ flock = struct.pack('lxxxxlxxxxlhh', \
+ l_start, l_len, os.getpid(), l_type, l_whence)
elif sys.platform in ['aix3', 'aix4']:
flock = struct.pack('hhlllii', \
l_type, l_whence, l_start, l_len, 0, 0, 0)
- else:
- flock = struct.pack('hhllhh', \
- l_type, l_whence, l_start, l_len, 0, 0)
+ else:
+ flock = struct.pack('hhllhh', \
+ l_type, l_whence, l_start, l_len, 0, 0)
- flock = fcntl.fcntl(self._file_.fileno(), cmd, flock)
+ flock = fcntl.fcntl(self._file_.fileno(), cmd, flock)
- if '?' in how:
- if sys.platform in ('netbsd1', 'freebsd2', 'freebsd3'):
- l_start, l_len, l_pid, l_type, l_whence = \
- struct.unpack('lxxxxlxxxxlhh', flock)
+ if '?' in how:
+ if sys.platform in ('netbsd1', 'freebsd2', 'freebsd3'):
+ l_start, l_len, l_pid, l_type, l_whence = \
+ struct.unpack('lxxxxlxxxxlhh', flock)
elif sys.platform in ['aix3', 'aix4']:
l_type, l_whence, l_start, l_len, l_sysid, l_pid, l_vfs = \
struct.unpack('hhlllii', flock)
- elif sys.platform == "linux2":
- l_type, l_whence, l_start, l_len, l_pid, l_sysid = \
- struct.unpack('hhllhh', flock)
- else:
- l_type, l_whence, l_start, l_len, l_sysid, l_pid = \
- struct.unpack('hhllhh', flock)
-
- if l_type != FCNTL.F_UNLCK:
- if l_type == FCNTL.F_RDLCK:
- return 'r', l_len, l_start, l_whence, l_pid
- else:
- return 'w', l_len, l_start, l_whence, l_pid
+ elif sys.platform == "linux2":
+ l_type, l_whence, l_start, l_len, l_pid, l_sysid = \
+ struct.unpack('hhllhh', flock)
+ else:
+ l_type, l_whence, l_start, l_len, l_sysid, l_pid = \
+ struct.unpack('hhllhh', flock)
+
+ if l_type != FCNTL.F_UNLCK:
+ if l_type == FCNTL.F_RDLCK:
+ return 'r', l_len, l_start, l_whence, l_pid
+ else:
+ return 'w', l_len, l_start, l_whence, l_pid
#
# Public routine to obtain a posixfile object
-# Author: Fred L. Drake, Jr.
-# fdrake@cnri.reston.va.us, fdrake@acm.org
+# Author: Fred L. Drake, Jr.
+# fdrake@cnri.reston.va.us, fdrake@acm.org
#
# This is a simple little module I wrote to make life easier. I didn't
# see anything quite like it in the library, though I may have overlooked
class PrettyPrinter:
def __init__(self, indent=1, width=80, depth=None, stream=None):
- """Handle pretty printing operations onto a stream using a set of
- configured parameters.
-
- indent
- Number of spaces to indent for each level of nesting.
-
- width
- Attempted maximum number of columns in the output.
-
- depth
- The maximum depth to print out nested structures.
-
- stream
- The desired output stream. If omitted (or false), the standard
- output stream available at construction will be used.
-
- """
- indent = int(indent)
- width = int(width)
- assert indent >= 0
- assert (not depth) or depth > 0, "depth may not be negative"
- assert width
- self.__depth = depth
- self.__indent_per_level = indent
- self.__width = width
- if stream:
- self.__stream = stream
- else:
- import sys
- self.__stream = sys.stdout
+ """Handle pretty printing operations onto a stream using a set of
+ configured parameters.
+
+ indent
+ Number of spaces to indent for each level of nesting.
+
+ width
+ Attempted maximum number of columns in the output.
+
+ depth
+ The maximum depth to print out nested structures.
+
+ stream
+ The desired output stream. If omitted (or false), the standard
+ output stream available at construction will be used.
+
+ """
+ indent = int(indent)
+ width = int(width)
+ assert indent >= 0
+ assert (not depth) or depth > 0, "depth may not be negative"
+ assert width
+ self.__depth = depth
+ self.__indent_per_level = indent
+ self.__width = width
+ if stream:
+ self.__stream = stream
+ else:
+ import sys
+ self.__stream = sys.stdout
def pprint(self, object):
- self.__stream.write(self.pformat(object) + "\n")
+ self.__stream.write(self.pformat(object) + "\n")
def pformat(self, object):
- sio = StringIO()
- self.__format(object, sio, 0, 0, {}, 0)
- return sio.getvalue()
+ sio = StringIO()
+ self.__format(object, sio, 0, 0, {}, 0)
+ return sio.getvalue()
def isrecursive(self, object):
- self.__recursive = 0
- self.pformat(object)
- return self.__recursive
+ self.__recursive = 0
+ self.pformat(object)
+ return self.__recursive
def isreadable(self, object):
- self.__recursive = 0
- self.__readable = 1
- self.pformat(object)
- return self.__readable and not self.__recursive
+ self.__recursive = 0
+ self.__readable = 1
+ self.pformat(object)
+ return self.__readable and not self.__recursive
def __format(self, object, stream, indent, allowance, context, level):
- level = level + 1
- if context.has_key(id(object)):
- object = _Recursion(object)
- self.__recursive = 1
- rep = self.__repr(object, context, level - 1)
- objid = id(object)
- context[objid] = 1
- typ = type(object)
- sepLines = len(rep) > (self.__width - 1 - indent - allowance)
-
- if sepLines and typ in (ListType, TupleType):
- # Pretty-print the sequence.
- stream.write((typ is ListType) and '[' or '(')
- if self.__indent_per_level > 1:
- stream.write((self.__indent_per_level - 1) * ' ')
- length = len(object)
- if length:
- indent = indent + self.__indent_per_level
- self.__format(object[0], stream, indent, allowance + 1,
- context, level)
- if len(object) > 1:
- for ent in object[1:]:
- stream.write(',\n' + ' '*indent)
- self.__format(ent, stream, indent,
- allowance + 1, context, level)
- indent = indent - self.__indent_per_level
- if typ is TupleType and length == 1:
- stream.write(',')
- stream.write(((typ is ListType) and ']') or ')')
-
- elif sepLines and typ is DictType:
- stream.write('{')
- if self.__indent_per_level > 1:
- stream.write((self.__indent_per_level - 1) * ' ')
- length = len(object)
- if length:
- indent = indent + self.__indent_per_level
- items = object.items()
- items.sort()
- key, ent = items[0]
- rep = self.__repr(key, context, level) + ': '
- stream.write(rep)
- self.__format(ent, stream, indent + len(rep),
- allowance + 1, context, level)
- if len(items) > 1:
- for key, ent in items[1:]:
- rep = self.__repr(key, context, level) + ': '
- stream.write(',\n' + ' '*indent + rep)
- self.__format(ent, stream, indent + len(rep),
- allowance + 1, context, level)
- indent = indent - self.__indent_per_level
- stream.write('}')
-
- else:
- stream.write(rep)
- del context[objid]
+ level = level + 1
+ if context.has_key(id(object)):
+ object = _Recursion(object)
+ self.__recursive = 1
+ rep = self.__repr(object, context, level - 1)
+ objid = id(object)
+ context[objid] = 1
+ typ = type(object)
+ sepLines = len(rep) > (self.__width - 1 - indent - allowance)
+
+ if sepLines and typ in (ListType, TupleType):
+ # Pretty-print the sequence.
+ stream.write((typ is ListType) and '[' or '(')
+ if self.__indent_per_level > 1:
+ stream.write((self.__indent_per_level - 1) * ' ')
+ length = len(object)
+ if length:
+ indent = indent + self.__indent_per_level
+ self.__format(object[0], stream, indent, allowance + 1,
+ context, level)
+ if len(object) > 1:
+ for ent in object[1:]:
+ stream.write(',\n' + ' '*indent)
+ self.__format(ent, stream, indent,
+ allowance + 1, context, level)
+ indent = indent - self.__indent_per_level
+ if typ is TupleType and length == 1:
+ stream.write(',')
+ stream.write(((typ is ListType) and ']') or ')')
+
+ elif sepLines and typ is DictType:
+ stream.write('{')
+ if self.__indent_per_level > 1:
+ stream.write((self.__indent_per_level - 1) * ' ')
+ length = len(object)
+ if length:
+ indent = indent + self.__indent_per_level
+ items = object.items()
+ items.sort()
+ key, ent = items[0]
+ rep = self.__repr(key, context, level) + ': '
+ stream.write(rep)
+ self.__format(ent, stream, indent + len(rep),
+ allowance + 1, context, level)
+ if len(items) > 1:
+ for key, ent in items[1:]:
+ rep = self.__repr(key, context, level) + ': '
+ stream.write(',\n' + ' '*indent + rep)
+ self.__format(ent, stream, indent + len(rep),
+ allowance + 1, context, level)
+ indent = indent - self.__indent_per_level
+ stream.write('}')
+
+ else:
+ stream.write(rep)
+ del context[objid]
def __repr(self, object, context, level):
- repr, readable = _safe_repr(object, context, self.__depth, level)
- if not readable:
- self.__readable = 0
- return repr
+ repr, readable = _safe_repr(object, context, self.__depth, level)
+ if not readable:
+ self.__readable = 0
+ return repr
def _safe_repr(object, context, maxlevels=None, level=0):
readable = 1
typ = type(object)
if not (typ in (DictType, ListType, TupleType) and object):
- rep = `object`
- if rep:
- if rep[0] == '<':
- readable = 0
- else:
- readable = 0
- return `object`, readable
+ rep = `object`
+ if rep:
+ if rep[0] == '<':
+ readable = 0
+ else:
+ readable = 0
+ return `object`, readable
if context.has_key(id(object)):
- return `_Recursion(object)`, 0
+ return `_Recursion(object)`, 0
objid = id(object)
context[objid] = 1
if typ is DictType:
- if maxlevels and level >= maxlevels:
- s = "{...}"
- readable = 0
- else:
- items = object.items()
- k, v = items[0]
- krepr, kreadable = _safe_repr(k, context, maxlevels, level)
- vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
- readable = readable and kreadable and vreadable
- s = "{%s: %s" % (krepr, vrepr)
- for k, v in items[1:]:
- krepr, kreadable = _safe_repr(k, context, maxlevels, level)
- vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
- readable = readable and kreadable and vreadable
- s = "%s, %s: %s" % (s, krepr, vrepr)
- s = s + "}"
+ if maxlevels and level >= maxlevels:
+ s = "{...}"
+ readable = 0
+ else:
+ items = object.items()
+ k, v = items[0]
+ krepr, kreadable = _safe_repr(k, context, maxlevels, level)
+ vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
+ readable = readable and kreadable and vreadable
+ s = "{%s: %s" % (krepr, vrepr)
+ for k, v in items[1:]:
+ krepr, kreadable = _safe_repr(k, context, maxlevels, level)
+ vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
+ readable = readable and kreadable and vreadable
+ s = "%s, %s: %s" % (s, krepr, vrepr)
+ s = s + "}"
else:
- s, term = (typ is ListType) and ('[', ']') or ('(', ')')
- if maxlevels and level >= maxlevels:
- s = s + "..."
- readable = 0
- else:
- subrepr, subreadable = _safe_repr(
- object[0], context, maxlevels, level)
- readable = readable and subreadable
- s = s + subrepr
- tail = object[1:]
- if not tail:
- if typ is TupleType:
- s = s + ','
- for ent in tail:
- subrepr, subreadable = _safe_repr(
- ent, context, maxlevels, level)
- readable = readable and subreadable
- s = "%s, %s" % (s, subrepr)
- s = s + term
+ s, term = (typ is ListType) and ('[', ']') or ('(', ')')
+ if maxlevels and level >= maxlevels:
+ s = s + "..."
+ readable = 0
+ else:
+ subrepr, subreadable = _safe_repr(
+ object[0], context, maxlevels, level)
+ readable = readable and subreadable
+ s = s + subrepr
+ tail = object[1:]
+ if not tail:
+ if typ is TupleType:
+ s = s + ','
+ for ent in tail:
+ subrepr, subreadable = _safe_repr(
+ ent, context, maxlevels, level)
+ readable = readable and subreadable
+ s = "%s, %s" % (s, subrepr)
+ s = s + term
del context[objid]
return s, readable
# represent a recursive relationship; really only used for the __repr__()
# method...
def __init__(self, object):
- self.__repr = "<Recursion on %s with id=%s>" \
- % (type(object).__name__, id(object))
+ self.__repr = "<Recursion on %s with id=%s>" \
+ % (type(object).__name__, id(object))
def __repr__(self):
- return self.__repr
+ return self.__repr
file: source filename
cfile: target filename; defaults to source with 'c' or 'o' appended
- ('c' normally, 'o' in optimizing mode, giving .pyc or .pyo)
+ ('c' normally, 'o' in optimizing mode, giving .pyc or .pyo)
dfile: purported filename; defaults to source (this is the filename
- that will show up in error messages)
+ that will show up in error messages)
Note that it isn't necessary to byte-compile Python modules for
execution efficiency -- Python itself byte-compiles a module when
import os, marshal, __builtin__
f = open(file)
try:
- timestamp = os.fstat(file.fileno())
+ timestamp = os.fstat(file.fileno())
except AttributeError:
- timestamp = long(os.stat(file)[8])
+ timestamp = long(os.stat(file)[8])
codestring = f.read()
f.close()
if codestring and codestring[-1] != '\n':
- codestring = codestring + '\n'
+ codestring = codestring + '\n'
codeobject = __builtin__.compile(codestring, dfile or file, 'exec')
if not cfile:
- cfile = file + (__debug__ and 'c' or 'o')
+ cfile = file + (__debug__ and 'c' or 'o')
fc = open(cfile, 'wb')
fc.write('\0\0\0\0')
wr_long(fc, timestamp)
fc.write(MAGIC)
fc.close()
if os.name == 'mac':
- import macfs
- macfs.FSSpec(cfile).SetCreatorType('Pyth', 'PYC ')
- macfs.FSSpec(file).SetCreatorType('Pyth', 'TEXT')
+ import macfs
+ macfs.FSSpec(cfile).SetCreatorType('Pyth', 'PYC ')
+ macfs.FSSpec(file).SetCreatorType('Pyth', 'TEXT')
def _cachecompile(pattern, flags=0):
key = (pattern, flags)
try:
- return _cache[key]
+ return _cache[key]
except KeyError:
- pass
+ pass
value = compile(pattern, flags)
if len(_cache) >= _MAXCACHE:
- _cache.clear()
+ _cache.clear()
_cache[key] = value
return value
def sub(pattern, repl, string, count=0):
if type(pattern) == type(''):
- pattern = _cachecompile(pattern)
+ pattern = _cachecompile(pattern)
return pattern.sub(repl, string, count)
def subn(pattern, repl, string, count=0):
if type(pattern) == type(''):
- pattern = _cachecompile(pattern)
+ pattern = _cachecompile(pattern)
return pattern.subn(repl, string, count)
def split(pattern, string, maxsplit=0):
if type(pattern) == type(''):
- pattern = _cachecompile(pattern)
+ pattern = _cachecompile(pattern)
return pattern.split(string, maxsplit)
def escape(pattern):
result = []
alphanum=string.letters+'_'+string.digits
for char in pattern:
- if char not in alphanum:
- if char == '\000': result.append(r'\000')
- else: result.append('\\' + char)
- else: result.append(char)
+ if char not in alphanum:
+ if char == '\000': result.append(r'\000')
+ else: result.append('\\' + char)
+ else: result.append(char)
return string.join(result, '')
def compile(pattern, flags=0):
class RegexObject:
def __init__(self, pattern, flags, code, groupindex):
- self.code = code
- self.flags = flags
- self.pattern = pattern
- self.groupindex = groupindex
+ self.code = code
+ self.flags = flags
+ self.pattern = pattern
+ self.groupindex = groupindex
def search(self, string, pos=0, endpos=None):
- """Scan through string looking for a match to the pattern, returning
- a MatchObject instance, or None if no match was found."""
+ """Scan through string looking for a match to the pattern, returning
+ a MatchObject instance, or None if no match was found."""
- if endpos is None or endpos>len(string):
- endpos=len(string)
- if endpos<pos: endpos=pos
- regs = self.code.match(string, pos, endpos, 0)
- if regs is None:
- return None
- self._num_regs=len(regs)
-
- return MatchObject(self,
- string,
- pos, endpos,
- regs)
+ if endpos is None or endpos>len(string):
+ endpos=len(string)
+ if endpos<pos: endpos=pos
+ regs = self.code.match(string, pos, endpos, 0)
+ if regs is None:
+ return None
+ self._num_regs=len(regs)
+
+ return MatchObject(self,
+ string,
+ pos, endpos,
+ regs)
def match(self, string, pos=0, endpos=None):
- """Try to apply the pattern at the start of the string, returning
- a MatchObject instance, or None if no match was found."""
+ """Try to apply the pattern at the start of the string, returning
+ a MatchObject instance, or None if no match was found."""
- if endpos is None or endpos>len(string):
- endpos=len(string)
- if endpos<pos: endpos=pos
- regs = self.code.match(string, pos, endpos, ANCHORED)
- if regs is None:
- return None
- self._num_regs=len(regs)
- return MatchObject(self,
- string,
- pos, endpos,
- regs)
+ if endpos is None or endpos>len(string):
+ endpos=len(string)
+ if endpos<pos: endpos=pos
+ regs = self.code.match(string, pos, endpos, ANCHORED)
+ if regs is None:
+ return None
+ self._num_regs=len(regs)
+ return MatchObject(self,
+ string,
+ pos, endpos,
+ regs)
def sub(self, repl, string, count=0):
- """Return the string obtained by replacing the leftmost
- non-overlapping occurrences of the pattern in string by the
- replacement repl"""
+ """Return the string obtained by replacing the leftmost
+ non-overlapping occurrences of the pattern in string by the
+ replacement repl"""
return self.subn(repl, string, count)[0]
def subn(self, repl, source, count=0):
- """Return a 2-tuple containing (new_string, number).
- new_string is the string obtained by replacing the leftmost
- non-overlapping occurrences of the pattern in string by the
- replacement repl. number is the number of substitutions that
- were made."""
+ """Return a 2-tuple containing (new_string, number).
+ new_string is the string obtained by replacing the leftmost
+ non-overlapping occurrences of the pattern in string by the
+ replacement repl. number is the number of substitutions that
+ were made."""
- if count < 0:
- raise error, "negative substitution count"
- if count == 0:
- import sys
- count = sys.maxint
- if type(repl) == type(''):
- if '\\' in repl:
- repl = lambda m, r=repl: pcre_expand(m, r)
- else:
- repl = lambda m, r=repl: r
- n = 0 # Number of matches
- pos = 0 # Where to start searching
- lastmatch = -1 # End of last match
- results = [] # Substrings making up the result
- end = len(source)
- while n < count and pos <= end:
- m = self.search(source, pos)
- if not m:
- break
- i, j = m.span(0)
- if i == j == lastmatch:
- # Empty match adjacent to previous match
- pos = pos + 1
- results.append(source[lastmatch:pos])
- continue
- if pos < i:
- results.append(source[pos:i])
- results.append(repl(m))
- pos = lastmatch = j
- if i == j:
- # Last match was empty; don't try here again
- pos = pos + 1
- results.append(source[lastmatch:pos])
- n = n + 1
- results.append(source[pos:])
- return (string.join(results, ''), n)
-
+ if count < 0:
+ raise error, "negative substitution count"
+ if count == 0:
+ import sys
+ count = sys.maxint
+ if type(repl) == type(''):
+ if '\\' in repl:
+ repl = lambda m, r=repl: pcre_expand(m, r)
+ else:
+ repl = lambda m, r=repl: r
+ n = 0 # Number of matches
+ pos = 0 # Where to start searching
+ lastmatch = -1 # End of last match
+ results = [] # Substrings making up the result
+ end = len(source)
+ while n < count and pos <= end:
+ m = self.search(source, pos)
+ if not m:
+ break
+ i, j = m.span(0)
+ if i == j == lastmatch:
+ # Empty match adjacent to previous match
+ pos = pos + 1
+ results.append(source[lastmatch:pos])
+ continue
+ if pos < i:
+ results.append(source[pos:i])
+ results.append(repl(m))
+ pos = lastmatch = j
+ if i == j:
+ # Last match was empty; don't try here again
+ pos = pos + 1
+ results.append(source[lastmatch:pos])
+ n = n + 1
+ results.append(source[pos:])
+ return (string.join(results, ''), n)
+
def split(self, source, maxsplit=0):
- """Split \var{string} by the occurrences of the pattern,
- returning a list containing the resulting substrings."""
+ """Split \var{string} by the occurrences of the pattern,
+ returning a list containing the resulting substrings."""
- if maxsplit < 0:
- raise error, "negative split count"
- if maxsplit == 0:
- import sys
- maxsplit = sys.maxint
- n = 0
- pos = 0
- lastmatch = 0
- results = []
- end = len(source)
- while n < maxsplit:
- m = self.search(source, pos)
- if not m:
- break
- i, j = m.span(0)
- if i == j:
- # Empty match
- if pos >= end:
- break
- pos = pos+1
- continue
- results.append(source[lastmatch:i])
- g = m.groups()
- if g:
- if type(g)==type( "" ): g = [g]
- results[len(results):] = list(g)
- pos = lastmatch = j
- n = n + 1
- results.append(source[lastmatch:])
- return results
+ if maxsplit < 0:
+ raise error, "negative split count"
+ if maxsplit == 0:
+ import sys
+ maxsplit = sys.maxint
+ n = 0
+ pos = 0
+ lastmatch = 0
+ results = []
+ end = len(source)
+ while n < maxsplit:
+ m = self.search(source, pos)
+ if not m:
+ break
+ i, j = m.span(0)
+ if i == j:
+ # Empty match
+ if pos >= end:
+ break
+ pos = pos+1
+ continue
+ results.append(source[lastmatch:i])
+ g = m.groups()
+ if g:
+ if type(g)==type( "" ): g = [g]
+ results[len(results):] = list(g)
+ pos = lastmatch = j
+ n = n + 1
+ results.append(source[lastmatch:])
+ return results
# The following 3 functions were contributed by Mike Fletcher, and
# allow pickling and unpickling of RegexObject instances.
def __getinitargs__(self):
return (None,None,None,None) # any 4 elements, to work around
# problems with the
- # pickle/cPickle modules not yet
- # ignoring the __init__ function
+ # pickle/cPickle modules not yet
+ # ignoring the __init__ function
def __getstate__(self):
return self.pattern, self.flags, self.groupindex
def __setstate__(self, statetuple):
class MatchObject:
def __init__(self, re, string, pos, endpos, regs):
- self.re = re
- self.string = string
- self.pos = pos
- self.endpos = endpos
- self.regs = regs
-
+ self.re = re
+ self.string = string
+ self.pos = pos
+ self.endpos = endpos
+ self.regs = regs
+
def start(self, g = 0):
- "Return the start of the substring matched by group g"
- if type(g) == type(''):
- try:
- g = self.re.groupindex[g]
- except (KeyError, TypeError):
- raise IndexError, ('group "' + g + '" is undefined')
- return self.regs[g][0]
+ "Return the start of the substring matched by group g"
+ if type(g) == type(''):
+ try:
+ g = self.re.groupindex[g]
+ except (KeyError, TypeError):
+ raise IndexError, ('group "' + g + '" is undefined')
+ return self.regs[g][0]
def end(self, g = 0):
- "Return the end of the substring matched by group g"
- if type(g) == type(''):
- try:
- g = self.re.groupindex[g]
- except (KeyError, TypeError):
- raise IndexError, ('group "' + g + '" is undefined')
- return self.regs[g][1]
+ "Return the end of the substring matched by group g"
+ if type(g) == type(''):
+ try:
+ g = self.re.groupindex[g]
+ except (KeyError, TypeError):
+ raise IndexError, ('group "' + g + '" is undefined')
+ return self.regs[g][1]
def span(self, g = 0):
- """Return a tuple containing the start,end of the substring
- matched by group g"""
- if type(g) == type(''):
- try:
- g = self.re.groupindex[g]
- except (KeyError, TypeError):
- raise IndexError, ('group "' + g + '" is undefined')
- return self.regs[g]
+ """Return a tuple containing the start,end of the substring
+ matched by group g"""
+ if type(g) == type(''):
+ try:
+ g = self.re.groupindex[g]
+ except (KeyError, TypeError):
+ raise IndexError, ('group "' + g + '" is undefined')
+ return self.regs[g]
def groups(self):
- "Return a tuple containing all subgroups of the match object"
- result = []
- for g in range(1, self.re._num_regs):
- if (self.regs[g][0] == -1) or (self.regs[g][1] == -1):
- result.append(None)
- else:
- result.append(self.string[self.regs[g][0]:self.regs[g][1]])
- return tuple(result)
+ "Return a tuple containing all subgroups of the match object"
+ result = []
+ for g in range(1, self.re._num_regs):
+ if (self.regs[g][0] == -1) or (self.regs[g][1] == -1):
+ result.append(None)
+ else:
+ result.append(self.string[self.regs[g][0]:self.regs[g][1]])
+ return tuple(result)
def group(self, *groups):
- "Return one or more groups of the match."
- if len(groups) == 0:
- groups = (0,)
- result = []
- for g in groups:
- if type(g) == type(''):
- try:
- g = self.re.groupindex[g]
- except (KeyError, TypeError):
- raise IndexError, ('group "' + g + '" is undefined')
- if len(self.regs)<=g: raise IndexError, ('group "' + str(g) + '" is undefined')
- elif (self.regs[g][0] == -1) or (self.regs[g][1] == -1):
- result.append(None)
- else:
- result.append(self.string[self.regs[g][0]:self.regs[g][1]])
- if len(result) > 1:
- return tuple(result)
- elif len(result) == 1:
- return result[0]
- else:
- return ()
+ "Return one or more groups of the match."
+ if len(groups) == 0:
+ groups = (0,)
+ result = []
+ for g in groups:
+ if type(g) == type(''):
+ try:
+ g = self.re.groupindex[g]
+ except (KeyError, TypeError):
+ raise IndexError, ('group "' + g + '" is undefined')
+ if len(self.regs)<=g: raise IndexError, ('group "' + str(g) + '" is undefined')
+ elif (self.regs[g][0] == -1) or (self.regs[g][1] == -1):
+ result.append(None)
+ else:
+ result.append(self.string[self.regs[g][0]:self.regs[g][1]])
+ if len(result) > 1:
+ return tuple(result)
+ elif len(result) == 1:
+ return result[0]
+ else:
+ return ()
"""
table = mastertable.copy()
if syntax is None:
- syntax = regex.get_syntax()
+ syntax = regex.get_syntax()
if syntax & RE_NO_BK_PARENS:
- del table[r'\('], table[r'\)']
- del table['('], table[')']
+ del table[r'\('], table[r'\)']
+ del table['('], table[')']
if syntax & RE_NO_BK_VBAR:
- del table[r'\|']
- del table['|']
+ del table[r'\|']
+ del table['|']
if syntax & RE_BK_PLUS_QM:
- table['+'] = r'\+'
- table['?'] = r'\?'
- table[r'\+'] = '+'
- table[r'\?'] = '?'
+ table['+'] = r'\+'
+ table['?'] = r'\?'
+ table[r'\+'] = '+'
+ table[r'\?'] = '?'
if syntax & RE_NEWLINE_OR:
- table['\n'] = '|'
+ table['\n'] = '|'
res = ""
i = 0
end = len(s)
while i < end:
- c = s[i]
- i = i+1
- if c == '\\':
- c = s[i]
- i = i+1
- key = '\\' + c
- key = table.get(key, key)
- res = res + key
- else:
- c = table.get(c, c)
- res = res + c
+ c = s[i]
+ i = i+1
+ if c == '\\':
+ c = s[i]
+ i = i+1
+ key = '\\' + c
+ key = table.get(key, key)
+ res = res + key
+ else:
+ c = table.get(c, c)
+ res = res + c
return res
"""
if quote is None:
- q = "'"
- altq = "'"
- if q in s and altq not in s:
- q = altq
+ q = "'"
+ altq = "'"
+ if q in s and altq not in s:
+ q = altq
else:
- assert quote in ('"', "'")
- q = quote
+ assert quote in ('"', "'")
+ q = quote
res = q
for c in s:
- if c == q: c = '\\' + c
- elif c < ' ' or c > '~': c = "\\%03o" % ord(c)
- res = res + c
+ if c == q: c = '\\' + c
+ elif c < ' ' or c > '~': c = "\\%03o" % ord(c)
+ res = res + c
res = res + q
if '\\' in res:
- res = 'r' + res
+ res = 'r' + res
return res
s = eval(sys.stdin.read())
sys.stdout.write(quote(convert(s)))
if sys.stdout.isatty():
- sys.stdout.write("\n")
+ sys.stdout.write("\n")
if __name__ == '__main__':
# Parse a date field
_monthnames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
- 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+ 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
_daynames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
# The timezone table does not include the military time zones defined
# instead of timezone names.
_timezones = {'UT':0, 'UTC':0, 'GMT':0, 'Z':0,
- 'AST': -400, 'ADT': -300, # Atlantic standard
- 'EST': -500, 'EDT': -400, # Eastern
- 'CST': -600, 'CDT':-500, # Centreal
- 'MST':-700, 'MDT':-600, # Mountain
- 'PST':-800, 'PDT':-700 # Pacific
- }
+ 'AST': -400, 'ADT': -300, # Atlantic standard
+ 'EST': -500, 'EDT': -400, # Eastern
+ 'CST': -600, 'CDT':-500, # Centreal
+ 'MST':-700, 'MDT':-600, # Mountain
+ 'PST':-800, 'PDT':-700 # Pacific
+ }
def parsedate_tz(data):
pass
# Convert a timezone offset into seconds ; -0500 -> -18000
if tzoffset:
- if tzoffset < 0:
- tzsign = -1
- tzoffset = -tzoffset
- else:
- tzsign = 1
- tzoffset = tzsign * ( (tzoffset/100)*3600 + (tzoffset % 100)*60)
+ if tzoffset < 0:
+ tzsign = -1
+ tzoffset = -tzoffset
+ else:
+ tzsign = 1
+ tzoffset = tzsign * ( (tzoffset/100)*3600 + (tzoffset % 100)*60)
tuple = (yy, mm, dd, thh, tmm, tss, 0, 0, 0, tzoffset)
return tuple
"""
if data[9] is None:
- # No zone info, so localtime is better assumption than GMT
- return time.mktime(data[:8] + (-1,))
+ # No zone info, so localtime is better assumption than GMT
+ return time.mktime(data[:8] + (-1,))
else:
- t = time.mktime(data[:8] + (0,))
- return t - data[9] - time.timezone
+ t = time.mktime(data[:8] + (0,))
+ return t - data[9] - time.timezone
# When used as script, run a small test program.
class Completer:
def complete(self, text, state):
- """Return the next possible completion for 'text'.
+ """Return the next possible completion for 'text'.
- This is called successively with state == 0, 1, 2, ... until it
- returns None. The completion should begin with 'text'.
+ This is called successively with state == 0, 1, 2, ... until it
+ returns None. The completion should begin with 'text'.
- """
- if state == 0:
- if "." in text:
- self.matches = self.attr_matches(text)
- else:
- self.matches = self.global_matches(text)
- return self.matches[state]
+ """
+ if state == 0:
+ if "." in text:
+ self.matches = self.attr_matches(text)
+ else:
+ self.matches = self.global_matches(text)
+ return self.matches[state]
def global_matches(self, text):
- """Compute matches when text is a simple name.
-
- Return a list of all keywords, built-in functions and names
- currently defines in __main__ that match.
-
- """
- import keyword
- matches = []
- n = len(text)
- for list in [keyword.kwlist,
- __builtin__.__dict__.keys(),
- __main__.__dict__.keys()]:
- for word in list:
- if word[:n] == text:
- matches.append(word)
- return matches
+ """Compute matches when text is a simple name.
+
+ Return a list of all keywords, built-in functions and names
+ currently defines in __main__ that match.
+
+ """
+ import keyword
+ matches = []
+ n = len(text)
+ for list in [keyword.kwlist,
+ __builtin__.__dict__.keys(),
+ __main__.__dict__.keys()]:
+ for word in list:
+ if word[:n] == text:
+ matches.append(word)
+ return matches
def attr_matches(self, text):
- """Compute matches when text contains a dot.
-
- Assuming the text is of the form NAME.NAME....[NAME], and is
- evaluabable in the globals of __main__, it will be evaluated
- and its attributes (as revealed by dir()) are used as possible
- completions.
-
- WARNING: this can still invoke arbitrary C code, if an object
- with a __getattr__ hook is evaluated.
-
- """
- import re
- m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
- if not m:
- return
- expr, attr = m.group(1, 3)
- words = dir(eval(expr, __main__.__dict__))
- matches = []
- n = len(attr)
- for word in words:
- if word[:n] == attr:
- matches.append("%s.%s" % (expr, word))
- return matches
+ """Compute matches when text contains a dot.
+
+ Assuming the text is of the form NAME.NAME....[NAME], and is
+ evaluabable in the globals of __main__, it will be evaluated
+ and its attributes (as revealed by dir()) are used as possible
+ completions.
+
+ WARNING: this can still invoke arbitrary C code, if an object
+ with a __getattr__ hook is evaluated.
+
+ """
+ import re
+ m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
+ if not m:
+ return
+ expr, attr = m.group(1, 3)
+ words = dir(eval(expr, __main__.__dict__))
+ matches = []
+ n = len(attr)
+ for word in words:
+ if word[:n] == attr:
+ matches.append("%s.%s" % (expr, word))
+ return matches
readline.set_completer(Completer().complete)
interesting = re.compile('[&<]')
incomplete = re.compile('&([a-zA-Z][a-zA-Z0-9]*|#[0-9]*)?|'
- '<([a-zA-Z][^<>]*|'
- '/([a-zA-Z][^<>]*)?|'
- '![^<>]*)?')
+ '<([a-zA-Z][^<>]*|'
+ '/([a-zA-Z][^<>]*)?|'
+ '![^<>]*)?')
entityref = re.compile('&([a-zA-Z][a-zA-Z0-9]*)[^a-zA-Z0-9]')
charref = re.compile('&#([0-9]+)[^0-9]')
# Interface -- initialize and reset this instance
def __init__(self, verbose=0):
- self.verbose = verbose
- self.reset()
+ self.verbose = verbose
+ self.reset()
# Interface -- reset this instance. Loses all unprocessed data
def reset(self):
- self.rawdata = ''
- self.stack = []
- self.lasttag = '???'
- self.nomoretags = 0
- self.literal = 0
+ self.rawdata = ''
+ self.stack = []
+ self.lasttag = '???'
+ self.nomoretags = 0
+ self.literal = 0
# For derived classes only -- enter literal mode (CDATA) till EOF
def setnomoretags(self):
- self.nomoretags = self.literal = 1
+ self.nomoretags = self.literal = 1
# For derived classes only -- enter literal mode (CDATA)
def setliteral(self, *args):
- self.literal = 1
+ self.literal = 1
# Interface -- feed some data to the parser. Call this as
# often as you want, with as little or as much text as you
# want (may include '\n'). (This just saves the text, all the
# processing is done by goahead().)
def feed(self, data):
- self.rawdata = self.rawdata + data
- self.goahead(0)
+ self.rawdata = self.rawdata + data
+ self.goahead(0)
# Interface -- handle the remaining data
def close(self):
- self.goahead(1)
+ self.goahead(1)
# Internal -- handle data as far as reasonable. May leave state
# and data to be processed by a subsequent call. If 'end' is
# true, force handling all data as if followed by EOF marker.
def goahead(self, end):
- rawdata = self.rawdata
- i = 0
- n = len(rawdata)
- while i < n:
- if self.nomoretags:
- self.handle_data(rawdata[i:n])
- i = n
- break
- match = interesting.search(rawdata, i)
- if match: j = match.start(0)
- else: j = n
- if i < j: self.handle_data(rawdata[i:j])
- i = j
- if i == n: break
- if rawdata[i] == '<':
- if starttagopen.match(rawdata, i):
- if self.literal:
- self.handle_data(rawdata[i])
- i = i+1
- continue
- k = self.parse_starttag(i)
- if k < 0: break
- i = k
- continue
- if endtagopen.match(rawdata, i):
- k = self.parse_endtag(i)
- if k < 0: break
- i = k
- self.literal = 0
- continue
- if commentopen.match(rawdata, i):
- if self.literal:
- self.handle_data(rawdata[i])
- i = i+1
- continue
- k = self.parse_comment(i)
- if k < 0: break
- i = i+k
- continue
- match = special.match(rawdata, i)
- if match:
- if self.literal:
- self.handle_data(rawdata[i])
- i = i+1
- continue
- i = match.end(0)
- continue
- elif rawdata[i] == '&':
- match = charref.match(rawdata, i)
- if match:
- name = match.group(1)
- self.handle_charref(name)
- i = match.end(0)
- if rawdata[i-1] != ';': i = i-1
- continue
- match = entityref.match(rawdata, i)
- if match:
- name = match.group(1)
- self.handle_entityref(name)
- i = match.end(0)
- if rawdata[i-1] != ';': i = i-1
- continue
- else:
- raise RuntimeError, 'neither < nor & ??'
- # We get here only if incomplete matches but
- # nothing else
- match = incomplete.match(rawdata, i)
- if not match:
- self.handle_data(rawdata[i])
- i = i+1
- continue
- j = match.end(0)
- if j == n:
- break # Really incomplete
- self.handle_data(rawdata[i:j])
- i = j
- # end while
- if end and i < n:
- self.handle_data(rawdata[i:n])
- i = n
- self.rawdata = rawdata[i:]
- # XXX if end: check for empty stack
+ rawdata = self.rawdata
+ i = 0
+ n = len(rawdata)
+ while i < n:
+ if self.nomoretags:
+ self.handle_data(rawdata[i:n])
+ i = n
+ break
+ match = interesting.search(rawdata, i)
+ if match: j = match.start(0)
+ else: j = n
+ if i < j: self.handle_data(rawdata[i:j])
+ i = j
+ if i == n: break
+ if rawdata[i] == '<':
+ if starttagopen.match(rawdata, i):
+ if self.literal:
+ self.handle_data(rawdata[i])
+ i = i+1
+ continue
+ k = self.parse_starttag(i)
+ if k < 0: break
+ i = k
+ continue
+ if endtagopen.match(rawdata, i):
+ k = self.parse_endtag(i)
+ if k < 0: break
+ i = k
+ self.literal = 0
+ continue
+ if commentopen.match(rawdata, i):
+ if self.literal:
+ self.handle_data(rawdata[i])
+ i = i+1
+ continue
+ k = self.parse_comment(i)
+ if k < 0: break
+ i = i+k
+ continue
+ match = special.match(rawdata, i)
+ if match:
+ if self.literal:
+ self.handle_data(rawdata[i])
+ i = i+1
+ continue
+ i = match.end(0)
+ continue
+ elif rawdata[i] == '&':
+ match = charref.match(rawdata, i)
+ if match:
+ name = match.group(1)
+ self.handle_charref(name)
+ i = match.end(0)
+ if rawdata[i-1] != ';': i = i-1
+ continue
+ match = entityref.match(rawdata, i)
+ if match:
+ name = match.group(1)
+ self.handle_entityref(name)
+ i = match.end(0)
+ if rawdata[i-1] != ';': i = i-1
+ continue
+ else:
+ raise RuntimeError, 'neither < nor & ??'
+ # We get here only if incomplete matches but
+ # nothing else
+ match = incomplete.match(rawdata, i)
+ if not match:
+ self.handle_data(rawdata[i])
+ i = i+1
+ continue
+ j = match.end(0)
+ if j == n:
+ break # Really incomplete
+ self.handle_data(rawdata[i:j])
+ i = j
+ # end while
+ if end and i < n:
+ self.handle_data(rawdata[i:n])
+ i = n
+ self.rawdata = rawdata[i:]
+ # XXX if end: check for empty stack
# Internal -- parse comment, return length or -1 if not terminated
def parse_comment(self, i):
- rawdata = self.rawdata
- if rawdata[i:i+4] <> '<!--':
- raise RuntimeError, 'unexpected call to handle_comment'
- match = commentclose.search(rawdata, i+4)
- if not match:
- return -1
- j = match.start(0)
- self.handle_comment(rawdata[i+4: j])
- j = match.end(0)
- return j-i
+ rawdata = self.rawdata
+ if rawdata[i:i+4] <> '<!--':
+ raise RuntimeError, 'unexpected call to handle_comment'
+ match = commentclose.search(rawdata, i+4)
+ if not match:
+ return -1
+ j = match.start(0)
+ self.handle_comment(rawdata[i+4: j])
+ j = match.end(0)
+ return j-i
# Internal -- handle starttag, return length or -1 if not terminated
def parse_starttag(self, i):
- rawdata = self.rawdata
- if shorttagopen.match(rawdata, i):
- # SGML shorthand: <tag/data/ == <tag>data</tag>
- # XXX Can data contain &... (entity or char refs)?
- # XXX Can data contain < or > (tag characters)?
- # XXX Can there be whitespace before the first /?
- match = shorttag.match(rawdata, i)
- if not match:
- return -1
- tag, data = match.group(1, 2)
- tag = string.lower(tag)
- self.finish_shorttag(tag, data)
- k = match.end(0)
- return k
- # XXX The following should skip matching quotes (' or ")
- match = endbracket.search(rawdata, i+1)
- if not match:
- return -1
- j = match.start(0)
- # Now parse the data between i+1 and j into a tag and attrs
- attrs = []
- if rawdata[i:i+2] == '<>':
- # SGML shorthand: <> == <last open tag seen>
- k = j
- tag = self.lasttag
- else:
- match = tagfind.match(rawdata, i+1)
- if not match:
- raise RuntimeError, 'unexpected call to parse_starttag'
- k = match.end(0)
- tag = string.lower(rawdata[i+1:k])
- self.lasttag = tag
- while k < j:
- match = attrfind.match(rawdata, k)
- if not match: break
- attrname, rest, attrvalue = match.group(1, 2, 3)
- if not rest:
- attrvalue = attrname
- elif attrvalue[:1] == '\'' == attrvalue[-1:] or \
- attrvalue[:1] == '"' == attrvalue[-1:]:
- attrvalue = attrvalue[1:-1]
- attrs.append((string.lower(attrname), attrvalue))
- k = match.end(0)
- if rawdata[j] == '>':
- j = j+1
- self.finish_starttag(tag, attrs)
- return j
+ rawdata = self.rawdata
+ if shorttagopen.match(rawdata, i):
+ # SGML shorthand: <tag/data/ == <tag>data</tag>
+ # XXX Can data contain &... (entity or char refs)?
+ # XXX Can data contain < or > (tag characters)?
+ # XXX Can there be whitespace before the first /?
+ match = shorttag.match(rawdata, i)
+ if not match:
+ return -1
+ tag, data = match.group(1, 2)
+ tag = string.lower(tag)
+ self.finish_shorttag(tag, data)
+ k = match.end(0)
+ return k
+ # XXX The following should skip matching quotes (' or ")
+ match = endbracket.search(rawdata, i+1)
+ if not match:
+ return -1
+ j = match.start(0)
+ # Now parse the data between i+1 and j into a tag and attrs
+ attrs = []
+ if rawdata[i:i+2] == '<>':
+ # SGML shorthand: <> == <last open tag seen>
+ k = j
+ tag = self.lasttag
+ else:
+ match = tagfind.match(rawdata, i+1)
+ if not match:
+ raise RuntimeError, 'unexpected call to parse_starttag'
+ k = match.end(0)
+ tag = string.lower(rawdata[i+1:k])
+ self.lasttag = tag
+ while k < j:
+ match = attrfind.match(rawdata, k)
+ if not match: break
+ attrname, rest, attrvalue = match.group(1, 2, 3)
+ if not rest:
+ attrvalue = attrname
+ elif attrvalue[:1] == '\'' == attrvalue[-1:] or \
+ attrvalue[:1] == '"' == attrvalue[-1:]:
+ attrvalue = attrvalue[1:-1]
+ attrs.append((string.lower(attrname), attrvalue))
+ k = match.end(0)
+ if rawdata[j] == '>':
+ j = j+1
+ self.finish_starttag(tag, attrs)
+ return j
# Internal -- parse endtag
def parse_endtag(self, i):
- rawdata = self.rawdata
- match = endbracket.search(rawdata, i+1)
- if not match:
- return -1
- j = match.start(0)
- tag = string.lower(string.strip(rawdata[i+2:j]))
- if rawdata[j] == '>':
- j = j+1
- self.finish_endtag(tag)
- return j
+ rawdata = self.rawdata
+ match = endbracket.search(rawdata, i+1)
+ if not match:
+ return -1
+ j = match.start(0)
+ tag = string.lower(string.strip(rawdata[i+2:j]))
+ if rawdata[j] == '>':
+ j = j+1
+ self.finish_endtag(tag)
+ return j
# Internal -- finish parsing of <tag/data/ (same as <tag>data</tag>)
def finish_shorttag(self, tag, data):
- self.finish_starttag(tag, [])
- self.handle_data(data)
- self.finish_endtag(tag)
+ self.finish_starttag(tag, [])
+ self.handle_data(data)
+ self.finish_endtag(tag)
# Internal -- finish processing of start tag
# Return -1 for unknown tag, 0 for open-only tag, 1 for balanced tag
def finish_starttag(self, tag, attrs):
- try:
- method = getattr(self, 'start_' + tag)
- except AttributeError:
- try:
- method = getattr(self, 'do_' + tag)
- except AttributeError:
- self.unknown_starttag(tag, attrs)
- return -1
- else:
- self.handle_starttag(tag, method, attrs)
- return 0
- else:
- self.stack.append(tag)
- self.handle_starttag(tag, method, attrs)
- return 1
+ try:
+ method = getattr(self, 'start_' + tag)
+ except AttributeError:
+ try:
+ method = getattr(self, 'do_' + tag)
+ except AttributeError:
+ self.unknown_starttag(tag, attrs)
+ return -1
+ else:
+ self.handle_starttag(tag, method, attrs)
+ return 0
+ else:
+ self.stack.append(tag)
+ self.handle_starttag(tag, method, attrs)
+ return 1
# Internal -- finish processing of end tag
def finish_endtag(self, tag):
- if not tag:
- found = len(self.stack) - 1
- if found < 0:
- self.unknown_endtag(tag)
- return
- else:
- if tag not in self.stack:
- try:
- method = getattr(self, 'end_' + tag)
- except AttributeError:
- self.unknown_endtag(tag)
- return
- found = len(self.stack)
- for i in range(found):
- if self.stack[i] == tag: found = i
- while len(self.stack) > found:
- tag = self.stack[-1]
- try:
- method = getattr(self, 'end_' + tag)
- except AttributeError:
- method = None
- if method:
- self.handle_endtag(tag, method)
- else:
- self.unknown_endtag(tag)
- del self.stack[-1]
+ if not tag:
+ found = len(self.stack) - 1
+ if found < 0:
+ self.unknown_endtag(tag)
+ return
+ else:
+ if tag not in self.stack:
+ try:
+ method = getattr(self, 'end_' + tag)
+ except AttributeError:
+ self.unknown_endtag(tag)
+ return
+ found = len(self.stack)
+ for i in range(found):
+ if self.stack[i] == tag: found = i
+ while len(self.stack) > found:
+ tag = self.stack[-1]
+ try:
+ method = getattr(self, 'end_' + tag)
+ except AttributeError:
+ method = None
+ if method:
+ self.handle_endtag(tag, method)
+ else:
+ self.unknown_endtag(tag)
+ del self.stack[-1]
# Overridable -- handle start tag
def handle_starttag(self, tag, method, attrs):
- method(attrs)
+ method(attrs)
# Overridable -- handle end tag
def handle_endtag(self, tag, method):
- method()
+ method()
# Example -- report an unbalanced </...> tag.
def report_unbalanced(self, tag):
- if self.verbose:
- print '*** Unbalanced </' + tag + '>'
- print '*** Stack:', self.stack
+ if self.verbose:
+ print '*** Unbalanced </' + tag + '>'
+ print '*** Stack:', self.stack
# Example -- handle character reference, no need to override
def handle_charref(self, name):
- try:
- n = string.atoi(name)
- except string.atoi_error:
- self.unknown_charref(name)
- return
- if not 0 <= n <= 255:
- self.unknown_charref(name)
- return
- self.handle_data(chr(n))
+ try:
+ n = string.atoi(name)
+ except string.atoi_error:
+ self.unknown_charref(name)
+ return
+ if not 0 <= n <= 255:
+ self.unknown_charref(name)
+ return
+ self.handle_data(chr(n))
# Definition of entities -- derived classes may override
entitydefs = \
- {'lt': '<', 'gt': '>', 'amp': '&', 'quot': '"', 'apos': '\''}
+ {'lt': '<', 'gt': '>', 'amp': '&', 'quot': '"', 'apos': '\''}
# Example -- handle entity reference, no need to override
def handle_entityref(self, name):
- table = self.entitydefs
- if table.has_key(name):
- self.handle_data(table[name])
- else:
- self.unknown_entityref(name)
- return
+ table = self.entitydefs
+ if table.has_key(name):
+ self.handle_data(table[name])
+ else:
+ self.unknown_entityref(name)
+ return
# Example -- handle data, should be overridden
def handle_data(self, data):
- pass
+ pass
# Example -- handle comment, could be overridden
def handle_comment(self, data):
- pass
+ pass
# To be overridden -- handlers for unknown objects
def unknown_starttag(self, tag, attrs): pass
class TestSGMLParser(SGMLParser):
def __init__(self, verbose=0):
- self.testdata = ""
- SGMLParser.__init__(self, verbose)
+ self.testdata = ""
+ SGMLParser.__init__(self, verbose)
def handle_data(self, data):
- self.testdata = self.testdata + data
- if len(`self.testdata`) >= 70:
- self.flush()
+ self.testdata = self.testdata + data
+ if len(`self.testdata`) >= 70:
+ self.flush()
def flush(self):
- data = self.testdata
- if data:
- self.testdata = ""
- print 'data:', `data`
+ data = self.testdata
+ if data:
+ self.testdata = ""
+ print 'data:', `data`
def handle_comment(self, data):
- self.flush()
- r = `data`
- if len(r) > 68:
- r = r[:32] + '...' + r[-32:]
- print 'comment:', r
+ self.flush()
+ r = `data`
+ if len(r) > 68:
+ r = r[:32] + '...' + r[-32:]
+ print 'comment:', r
def unknown_starttag(self, tag, attrs):
- self.flush()
- if not attrs:
- print 'start tag: <' + tag + '>'
- else:
- print 'start tag: <' + tag,
- for name, value in attrs:
- print name + '=' + '"' + value + '"',
- print '>'
+ self.flush()
+ if not attrs:
+ print 'start tag: <' + tag + '>'
+ else:
+ print 'start tag: <' + tag,
+ for name, value in attrs:
+ print name + '=' + '"' + value + '"',
+ print '>'
def unknown_endtag(self, tag):
- self.flush()
- print 'end tag: </' + tag + '>'
+ self.flush()
+ print 'end tag: </' + tag + '>'
def unknown_entityref(self, ref):
- self.flush()
- print '*** unknown entity ref: &' + ref + ';'
+ self.flush()
+ print '*** unknown entity ref: &' + ref + ';'
def unknown_charref(self, ref):
- self.flush()
- print '*** unknown char ref: &#' + ref + ';'
+ self.flush()
+ print '*** unknown char ref: &#' + ref + ';'
def close(self):
- SGMLParser.close(self)
- self.flush()
+ SGMLParser.close(self)
+ self.flush()
def test(args = None):
import sys
if not args:
- args = sys.argv[1:]
+ args = sys.argv[1:]
if args and args[0] == '-s':
- args = args[1:]
- klass = SGMLParser
+ args = args[1:]
+ klass = SGMLParser
else:
- klass = TestSGMLParser
+ klass = TestSGMLParser
if args:
- file = args[0]
+ file = args[0]
else:
- file = 'test.html'
+ file = 'test.html'
if file == '-':
- f = sys.stdin
+ f = sys.stdin
else:
- try:
- f = open(file, 'r')
- except IOError, msg:
- print file, ":", msg
- sys.exit(1)
+ try:
+ f = open(file, 'r')
+ except IOError, msg:
+ print file, ":", msg
+ sys.exit(1)
data = f.read()
if f is not sys.stdin:
- f.close()
+ f.close()
x = klass()
for c in data:
- x.feed(c)
+ x.feed(c)
x.close()
fsrc = None
fdst = None
try:
- fsrc = open(src, 'rb')
- fdst = open(dst, 'wb')
- while 1:
- buf = fsrc.read(16*1024)
- if not buf:
- break
- fdst.write(buf)
+ fsrc = open(src, 'rb')
+ fdst = open(dst, 'wb')
+ while 1:
+ buf = fsrc.read(16*1024)
+ if not buf:
+ break
+ fdst.write(buf)
finally:
- if fdst:
- fdst.close()
- if fsrc:
- fsrc.close()
+ if fdst:
+ fdst.close()
+ if fsrc:
+ fsrc.close()
def copymode(src, dst):
"""Copy mode bits from src to dst"""
"""
if os.path.isdir(dst):
- dst = os.path.join(dst, os.path.basename(src))
+ dst = os.path.join(dst, os.path.basename(src))
copyfile(src, dst)
copymode(src, dst)
"""
if os.path.isdir(dst):
- dst = os.path.join(dst, os.path.basename(src))
+ dst = os.path.join(dst, os.path.basename(src))
copyfile(src, dst)
copystat(src, dst)
names = os.listdir(src)
os.mkdir(dst)
for name in names:
- srcname = os.path.join(src, name)
- dstname = os.path.join(dst, name)
- try:
- if symlinks and os.path.islink(srcname):
- linkto = os.readlink(srcname)
- os.symlink(linkto, dstname)
- elif os.path.isdir(srcname):
- copytree(srcname, dstname)
- else:
- copy2(srcname, dstname)
- # XXX What about devices, sockets etc.?
- except (IOError, os.error), why:
- print "Can't copy %s to %s: %s" % (`srcname`, `dstname`, str(why))
+ srcname = os.path.join(src, name)
+ dstname = os.path.join(dst, name)
+ try:
+ if symlinks and os.path.islink(srcname):
+ linkto = os.readlink(srcname)
+ os.symlink(linkto, dstname)
+ elif os.path.isdir(srcname):
+ copytree(srcname, dstname)
+ else:
+ copy2(srcname, dstname)
+ # XXX What about devices, sockets etc.?
+ except (IOError, os.error), why:
+ print "Can't copy %s to %s: %s" % (`srcname`, `dstname`, str(why))
def rmtree(path, ignore_errors=0, onerror=None):
"""Recursively delete a directory tree.
cmdtuples = []
_build_cmdtuple(path, cmdtuples)
for cmd in cmdtuples:
- try:
- apply(cmd[0], (cmd[1],))
- except:
- exc = sys.exc_info()
- if ignore_errors:
- pass
- elif onerror:
- onerror(cmd[0], cmd[1], exc)
- else:
- raise exc[0], (exc[1][0], exc[1][1] + ' removing '+cmd[1])
+ try:
+ apply(cmd[0], (cmd[1],))
+ except:
+ exc = sys.exc_info()
+ if ignore_errors:
+ pass
+ elif onerror:
+ onerror(cmd[0], cmd[1], exc)
+ else:
+ raise exc[0], (exc[1][0], exc[1][1] + ' removing '+cmd[1])
# Helper for rmtree()
def _build_cmdtuple(path, cmdtuples):
for f in os.listdir(path):
- real_f = os.path.join(path,f)
- if os.path.isdir(real_f) and not os.path.islink(real_f):
- _build_cmdtuple(real_f, cmdtuples)
- else:
- cmdtuples.append(os.remove, real_f)
+ real_f = os.path.join(path,f)
+ if os.path.isdir(real_f) and not os.path.islink(real_f):
+ _build_cmdtuple(real_f, cmdtuples)
+ else:
+ cmdtuples.append(os.remove, real_f)
cmdtuples.append(os.rmdir, path)
def addsitedir(sitedir):
if sitedir not in sys.path:
- sys.path.append(sitedir) # Add path component
+ sys.path.append(sitedir) # Add path component
try:
- names = os.listdir(sitedir)
+ names = os.listdir(sitedir)
except os.error:
- return
+ return
names = map(os.path.normcase, names)
names.sort()
for name in names:
- if name[-4:] == ".pth":
- addpackage(sitedir, name)
+ if name[-4:] == ".pth":
+ addpackage(sitedir, name)
def addpackage(sitedir, name):
fullname = os.path.join(sitedir, name)
try:
- f = open(fullname)
+ f = open(fullname)
except IOError:
- return
+ return
while 1:
- dir = f.readline()
- if not dir:
- break
- if dir[0] == '#':
- continue
- if dir[-1] == '\n':
- dir = dir[:-1]
- dir = os.path.join(sitedir, dir)
- if dir not in sys.path and os.path.exists(dir):
- sys.path.append(dir)
+ dir = f.readline()
+ if not dir:
+ break
+ if dir[0] == '#':
+ continue
+ if dir[-1] == '\n':
+ dir = dir[:-1]
+ dir = os.path.join(sitedir, dir)
+ if dir not in sys.path and os.path.exists(dir):
+ sys.path.append(dir)
prefixes = [sys.prefix]
if sys.exec_prefix != sys.prefix:
prefixes.append(sys.exec_prefix)
for prefix in prefixes:
if prefix:
- if os.sep == '/':
- sitedirs = [os.path.join(prefix,
- "lib",
- "python" + sys.version[:3],
- "site-packages"),
- os.path.join(prefix, "lib", "site-python")]
- else:
- sitedirs = [prefix]
- for sitedir in sitedirs:
- if os.path.isdir(sitedir):
- addsitedir(sitedir)
+ if os.sep == '/':
+ sitedirs = [os.path.join(prefix,
+ "lib",
+ "python" + sys.version[:3],
+ "site-packages"),
+ os.path.join(prefix, "lib", "site-python")]
+ else:
+ sitedirs = [prefix]
+ for sitedir in sitedirs:
+ if os.path.isdir(sitedir):
+ addsitedir(sitedir)
try:
- import sitecustomize # Run arbitrary site specific code
+ import sitecustomize # Run arbitrary site specific code
except ImportError:
- pass # No site customization module
+ pass # No site customization module
def _test():
print "sys.path = ["
for dir in sys.path:
- print " %s," % `dir`
+ print " %s," % `dir`
print "]"
if __name__ == '__main__':
"""
self.debuglevel = 0
self.file = None
- self.helo_resp = None
+ self.helo_resp = None
if host: self.connect(host, port)
def set_debuglevel(self, debuglevel):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if self.debuglevel > 0: print 'connect:', (host, port)
self.sock.connect(host, port)
- (code,msg)=self.getreply()
- if self.debuglevel >0 : print "connect:", msg
- return msg
+ (code,msg)=self.getreply()
+ if self.debuglevel >0 : print "connect:", msg
+ return msg
def send(self, str):
"""Send `str' to the server."""
if self.debuglevel > 0: print 'send:', `str`
- if self.sock:
+ if self.sock:
self.sock.send(str)
else:
- raise SMTPServerDisconnected
+ raise SMTPServerDisconnected
def putcmd(self, cmd, args=""):
"""Send a command to the server.
- server response code (e.g. '250', or such, if all goes well)
Note: returns -1 if it can't read responce code.
- server response string corresponding to response code
- (note : multiline responces converted to a single,
+ (note : multiline responces converted to a single,
multiline string)
"""
resp=[]
- self.file = self.sock.makefile('rb')
- while 1:
+ self.file = self.sock.makefile('rb')
+ while 1:
line = self.file.readline()
if self.debuglevel > 0: print 'reply:', `line`
- resp.append(string.strip(line[4:]))
- code=line[:3]
- #check if multiline resp
- if line[3:4]!="-":
+ resp.append(string.strip(line[4:]))
+ code=line[:3]
+ #check if multiline resp
+ if line[3:4]!="-":
break
try:
errcode = string.atoi(code)
except(ValueError):
- errcode = -1
+ errcode = -1
- errmsg = string.join(resp,"\n")
- if self.debuglevel > 0:
+ errmsg = string.join(resp,"\n")
+ if self.debuglevel > 0:
print 'reply: retcode (%s); Msg: %s' % (errcode,errmsg)
return errcode, errmsg
def docmd(self, cmd, args=""):
- """ Send a command, and return it's responce code """
-
- self.putcmd(cmd,args)
- (code,msg)=self.getreply()
- return code
+ """ Send a command, and return it's responce code """
+
+ self.putcmd(cmd,args)
+ (code,msg)=self.getreply()
+ return code
# std smtp commands
def helo(self, name=''):
""" SMTP 'helo' command. Hostname to send for this command
defaults to the FQDN of the local host """
- name=string.strip(name)
- if len(name)==0:
- name=socket.gethostbyaddr(socket.gethostname())[0]
- self.putcmd("helo",name)
- (code,msg)=self.getreply()
- self.helo_resp=msg
- return code
+ name=string.strip(name)
+ if len(name)==0:
+ name=socket.gethostbyaddr(socket.gethostname())[0]
+ self.putcmd("helo",name)
+ (code,msg)=self.getreply()
+ self.helo_resp=msg
+ return code
def help(self):
- """ SMTP 'help' command. Returns help text from server """
- self.putcmd("help")
- (code,msg)=self.getreply()
- return msg
+ """ SMTP 'help' command. Returns help text from server """
+ self.putcmd("help")
+ (code,msg)=self.getreply()
+ return msg
def rset(self):
""" SMTP 'rset' command. Resets session. """
- code=self.docmd("rset")
- return code
+ code=self.docmd("rset")
+ return code
def noop(self):
""" SMTP 'noop' command. Dosen't do anything :> """
- code=self.docmd("noop")
- return code
+ code=self.docmd("noop")
+ return code
def mail(self,sender):
""" SMTP 'mail' command. Begins mail xfer session. """
self.putcmd("mail","from: %s" % sender)
- return self.getreply()
+ return self.getreply()
def rcpt(self,recip):
""" SMTP 'rcpt' command. Indicates 1 recipient for this mail. """
- self.putcmd("rcpt","to: %s" % recip)
- return self.getreply()
+ self.putcmd("rcpt","to: %s" % recip)
+ return self.getreply()
def data(self,msg):
""" SMTP 'DATA' command. Sends message data to server.
Automatically quotes lines beginning with a period per rfc821 """
- #quote periods in msg according to RFC821
+ #quote periods in msg according to RFC821
# ps, I don't know why I have to do it this way... doing:
- # quotepat=re.compile(r"^[.]",re.M)
- # msg=re.sub(quotepat,"..",msg)
+ # quotepat=re.compile(r"^[.]",re.M)
+ # msg=re.sub(quotepat,"..",msg)
# should work, but it dosen't (it doubles the number of any
# contiguous series of .'s at the beginning of a line,
#instead of just adding one. )
- quotepat=re.compile(r"^[.]+",re.M)
+ quotepat=re.compile(r"^[.]+",re.M)
def m(pat):
return "."+pat.group(0)
- msg=re.sub(quotepat,m,msg)
- self.putcmd("data")
- (code,repl)=self.getreply()
- if self.debuglevel >0 : print "data:", (code,repl)
- if code <> 354:
- return -1
- else:
- self.send(msg)
- self.send("\n.\n")
- (code,msg)=self.getreply()
- if self.debuglevel >0 : print "data:", (code,msg)
+ msg=re.sub(quotepat,m,msg)
+ self.putcmd("data")
+ (code,repl)=self.getreply()
+ if self.debuglevel >0 : print "data:", (code,repl)
+ if code <> 354:
+ return -1
+ else:
+ self.send(msg)
+ self.send("\n.\n")
+ (code,msg)=self.getreply()
+ if self.debuglevel >0 : print "data:", (code,msg)
return code
#some usefull methods
def sendmail(self,from_addr,to_addrs,msg):
""" This command performs an entire mail transaction.
- The arguments are:
+ The arguments are:
- from_addr : The address sending this mail.
- to_addrs : a list of addresses to send this mail to
- msg : the message to send.
- This method will return normally if the mail is accepted for at least
+ This method will return normally if the mail is accepted for at least
one recipiant.
Otherwise it will throw an exception (either SMTPSenderRefused,
SMTPRecipientsRefused, or SMTPDataError)
- That is, if this method does not throw an exception, then someone
+ That is, if this method does not throw an exception, then someone
should get your mail.
- It returns a dictionary , with one entry for each recipient that was
+ It returns a dictionary , with one entry for each recipient that was
refused.
example:
will return an empty dictionary.
"""
- if not self.helo_resp:
- self.helo()
+ if not self.helo_resp:
+ self.helo()
(code,resp)=self.mail(from_addr)
if code <>250:
- self.rset()
- raise SMTPSenderRefused
- senderrs={}
+ self.rset()
+ raise SMTPSenderRefused
+ senderrs={}
for each in to_addrs:
- (code,resp)=self.rcpt(each)
- if (code <> 250) and (code <> 251):
+ (code,resp)=self.rcpt(each)
+ if (code <> 250) and (code <> 251):
senderrs[each]=(code,resp)
if len(senderrs)==len(to_addrs):
- #th' server refused all our recipients
+ #th' server refused all our recipients
self.rset()
raise SMTPRecipientsRefused
code=self.data(msg)
- if code <>250 :
+ if code <>250 :
self.rset()
- raise SMTPDataError
+ raise SMTPDataError
#if we got here then somebody got our mail
- return senderrs
+ return senderrs
def close(self):
def quit(self):
- self.docmd("quit")
- self.close()
+ self.docmd("quit")
+ self.close()
sym_name = {}
for _name, _value in globals().items():
if type(_value) is type(0):
- sym_name[_value] = _name
+ sym_name[_value] = _name
def main():
import sys
import token
if len(sys.argv) == 1:
- sys.argv = sys.argv + ["Include/graminit.h", "Lib/symbol.py"]
+ sys.argv = sys.argv + ["Include/graminit.h", "Lib/symbol.py"]
token.main()
if __name__ == "__main__":
read_until(expected, [timeout])
Read until the expected string has been seen, or a timeout is
- hit (default is no timeout); may block.
+ hit (default is no timeout); may block.
read_all()
Read all data until EOF; may block.
read_very_eager()
Read all data available already queued or on the socket,
- without blocking.
+ without blocking.
read_eager()
Read either data already queued or some data available on the
- socket, without blocking.
+ socket, without blocking.
read_lazy()
Read all data in the raw queue (processing it first), without
- doing any socket I/O.
+ doing any socket I/O.
read_very_lazy()
Reads all data in the cooked queue, without doing any socket
- I/O.
+ I/O.
"""
def __init__(self, host=None, port=0):
- """Constructor.
-
- When called without arguments, create an unconnected instance.
- With a hostname argument, it connects the instance; a port
- number is optional.
-
- """
- self.debuglevel = DEBUGLEVEL
- self.host = host
- self.port = port
- self.sock = None
- self.rawq = ''
- self.irawq = 0
- self.cookedq = ''
- self.eof = 0
- if host:
- self.open(host, port)
+ """Constructor.
+
+ When called without arguments, create an unconnected instance.
+ With a hostname argument, it connects the instance; a port
+ number is optional.
+
+ """
+ self.debuglevel = DEBUGLEVEL
+ self.host = host
+ self.port = port
+ self.sock = None
+ self.rawq = ''
+ self.irawq = 0
+ self.cookedq = ''
+ self.eof = 0
+ if host:
+ self.open(host, port)
def open(self, host, port=0):
- """Connect to a host.
+ """Connect to a host.
- The optional second argument is the port number, which
- defaults to the standard telnet port (23).
+ The optional second argument is the port number, which
+ defaults to the standard telnet port (23).
- Don't try to reopen an already connected instance.
+ Don't try to reopen an already connected instance.
- """
- self.eof = 0
- if not port:
- port = TELNET_PORT
- self.host = host
- self.port = port
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.sock.connect((self.host, self.port))
+ """
+ self.eof = 0
+ if not port:
+ port = TELNET_PORT
+ self.host = host
+ self.port = port
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock.connect((self.host, self.port))
def __del__(self):
- """Destructor -- close the connection."""
- self.close()
+ """Destructor -- close the connection."""
+ self.close()
def msg(self, msg, *args):
- """Print a debug message, when the debug level is > 0.
+ """Print a debug message, when the debug level is > 0.
- If extra arguments are present, they are substituted in the
- message using the standard string formatting operator.
+ If extra arguments are present, they are substituted in the
+ message using the standard string formatting operator.
- """
- if self.debuglevel > 0:
- print 'Telnet(%s,%d):' % (self.host, self.port),
- if args:
- print msg % args
- else:
- print msg
+ """
+ if self.debuglevel > 0:
+ print 'Telnet(%s,%d):' % (self.host, self.port),
+ if args:
+ print msg % args
+ else:
+ print msg
def set_debuglevel(self, debuglevel):
- """Set the debug level.
+ """Set the debug level.
- The higher it is, the more debug output you get (on sys.stdout).
+ The higher it is, the more debug output you get (on sys.stdout).
- """
- self.debuglevel = debuglevel
+ """
+ self.debuglevel = debuglevel
def close(self):
- """Close the connection."""
- if self.sock:
- self.sock.close()
- self.sock = 0
- self.eof = 1
+ """Close the connection."""
+ if self.sock:
+ self.sock.close()
+ self.sock = 0
+ self.eof = 1
def get_socket(self):
- """Return the socket object used internally."""
- return self.sock
+ """Return the socket object used internally."""
+ return self.sock
def fileno(self):
- """Return the fileno() of the socket object used internally."""
- return self.sock.fileno()
+ """Return the fileno() of the socket object used internally."""
+ return self.sock.fileno()
def write(self, buffer):
- """Write a string to the socket, doubling any IAC characters.
+ """Write a string to the socket, doubling any IAC characters.
- Can block if the connection is blocked. May raise
- socket.error if the connection is closed.
+ Can block if the connection is blocked. May raise
+ socket.error if the connection is closed.
- """
- if IAC in buffer:
- buffer = string.replace(buffer, IAC, IAC+IAC)
- self.msg("send %s", `buffer`)
- self.sock.send(buffer)
+ """
+ if IAC in buffer:
+ buffer = string.replace(buffer, IAC, IAC+IAC)
+ self.msg("send %s", `buffer`)
+ self.sock.send(buffer)
def read_until(self, match, timeout=None):
- """Read until a given string is encountered or until timeout.
-
- When no match is found, return whatever is available instead,
- possibly the empty string. Raise EOFError if the connection
- is closed and no cooked data is available.
-
- """
- n = len(match)
- self.process_rawq()
- i = string.find(self.cookedq, match)
- if i >= 0:
- i = i+n
- buf = self.cookedq[:i]
- self.cookedq = self.cookedq[i:]
- return buf
- s_reply = ([self], [], [])
- s_args = s_reply
- if timeout is not None:
- s_args = s_args + (timeout,)
- while not self.eof and apply(select.select, s_args) == s_reply:
- i = max(0, len(self.cookedq)-n)
- self.fill_rawq()
- self.process_rawq()
- i = string.find(self.cookedq, match, i)
- if i >= 0:
- i = i+n
- buf = self.cookedq[:i]
- self.cookedq = self.cookedq[i:]
- return buf
- return self.read_very_lazy()
+ """Read until a given string is encountered or until timeout.
+
+ When no match is found, return whatever is available instead,
+ possibly the empty string. Raise EOFError if the connection
+ is closed and no cooked data is available.
+
+ """
+ n = len(match)
+ self.process_rawq()
+ i = string.find(self.cookedq, match)
+ if i >= 0:
+ i = i+n
+ buf = self.cookedq[:i]
+ self.cookedq = self.cookedq[i:]
+ return buf
+ s_reply = ([self], [], [])
+ s_args = s_reply
+ if timeout is not None:
+ s_args = s_args + (timeout,)
+ while not self.eof and apply(select.select, s_args) == s_reply:
+ i = max(0, len(self.cookedq)-n)
+ self.fill_rawq()
+ self.process_rawq()
+ i = string.find(self.cookedq, match, i)
+ if i >= 0:
+ i = i+n
+ buf = self.cookedq[:i]
+ self.cookedq = self.cookedq[i:]
+ return buf
+ return self.read_very_lazy()
def read_all(self):
- """Read all data until EOF; block until connection closed."""
- self.process_rawq()
- while not self.eof:
- self.fill_rawq()
- self.process_rawq()
- buf = self.cookedq
- self.cookedq = ''
- return buf
+ """Read all data until EOF; block until connection closed."""
+ self.process_rawq()
+ while not self.eof:
+ self.fill_rawq()
+ self.process_rawq()
+ buf = self.cookedq
+ self.cookedq = ''
+ return buf
def read_some(self):
- """Read at least one byte of cooked data unless EOF is hit.
+ """Read at least one byte of cooked data unless EOF is hit.
- Return '' if EOF is hit. Block if no data is immediately
- available.
+ Return '' if EOF is hit. Block if no data is immediately
+ available.
- """
- self.process_rawq()
- while not self.cookedq and not self.eof:
- self.fill_rawq()
- self.process_rawq()
- buf = self.cookedq
- self.cookedq = ''
- return buf
+ """
+ self.process_rawq()
+ while not self.cookedq and not self.eof:
+ self.fill_rawq()
+ self.process_rawq()
+ buf = self.cookedq
+ self.cookedq = ''
+ return buf
def read_very_eager(self):
- """Read everything that's possible without blocking in I/O (eager).
-
- Raise EOFError if connection closed and no cooked data
- available. Return '' if no cooked data available otherwise.
- Don't block unless in the midst of an IAC sequence.
-
- """
- self.process_rawq()
- while not self.eof and self.sock_avail():
- self.fill_rawq()
- self.process_rawq()
- return self.read_very_lazy()
+ """Read everything that's possible without blocking in I/O (eager).
+
+ Raise EOFError if connection closed and no cooked data
+ available. Return '' if no cooked data available otherwise.
+ Don't block unless in the midst of an IAC sequence.
+
+ """
+ self.process_rawq()
+ while not self.eof and self.sock_avail():
+ self.fill_rawq()
+ self.process_rawq()
+ return self.read_very_lazy()
def read_eager(self):
- """Read readily available data.
+ """Read readily available data.
- Raise EOFError if connection closed and no cooked data
- available. Return '' if no cooked data available otherwise.
- Don't block unless in the midst of an IAC sequence.
+ Raise EOFError if connection closed and no cooked data
+ available. Return '' if no cooked data available otherwise.
+ Don't block unless in the midst of an IAC sequence.
- """
- self.process_rawq()
- while not self.cookedq and not self.eof and self.sock_avail():
- self.fill_rawq()
- self.process_rawq()
- return self.read_very_lazy()
+ """
+ self.process_rawq()
+ while not self.cookedq and not self.eof and self.sock_avail():
+ self.fill_rawq()
+ self.process_rawq()
+ return self.read_very_lazy()
def read_lazy(self):
- """Process and return data that's already in the queues (lazy).
-
- Raise EOFError if connection closed and no data available.
- Return '' if no cooked data available otherwise. Don't block
- unless in the midst of an IAC sequence.
+ """Process and return data that's already in the queues (lazy).
+
+ Raise EOFError if connection closed and no data available.
+ Return '' if no cooked data available otherwise. Don't block
+ unless in the midst of an IAC sequence.
- """
- self.process_rawq()
- return self.read_very_lazy()
+ """
+ self.process_rawq()
+ return self.read_very_lazy()
def read_very_lazy(self):
- """Return any data available in the cooked queue (very lazy).
+ """Return any data available in the cooked queue (very lazy).
- Raise EOFError if connection closed and no data available.
- Return '' if no cooked data available otherwise. Don't block.
+ Raise EOFError if connection closed and no data available.
+ Return '' if no cooked data available otherwise. Don't block.
- """
- buf = self.cookedq
- self.cookedq = ''
- if not buf and self.eof and not self.rawq:
- raise EOFError, 'telnet connection closed'
- return buf
+ """
+ buf = self.cookedq
+ self.cookedq = ''
+ if not buf and self.eof and not self.rawq:
+ raise EOFError, 'telnet connection closed'
+ return buf
def process_rawq(self):
- """Transfer from raw queue to cooked queue.
-
- Set self.eof when connection is closed. Don't block unless in
- the midst of an IAC sequence.
-
- """
- buf = ''
- try:
- while self.rawq:
- c = self.rawq_getchar()
- if c == theNULL:
- continue
- if c == "\021":
- continue
- if c != IAC:
- buf = buf + c
- continue
- c = self.rawq_getchar()
- if c == IAC:
- buf = buf + c
- elif c in (DO, DONT):
- opt = self.rawq_getchar()
- self.msg('IAC %s %d', c == DO and 'DO' or 'DONT', ord(c))
- self.sock.send(IAC + WONT + opt)
- elif c in (WILL, WONT):
- opt = self.rawq_getchar()
- self.msg('IAC %s %d',
- c == WILL and 'WILL' or 'WONT', ord(c))
- else:
- self.msg('IAC %s not recognized' % `c`)
- except EOFError: # raised by self.rawq_getchar()
- pass
- self.cookedq = self.cookedq + buf
+ """Transfer from raw queue to cooked queue.
+
+ Set self.eof when connection is closed. Don't block unless in
+ the midst of an IAC sequence.
+
+ """
+ buf = ''
+ try:
+ while self.rawq:
+ c = self.rawq_getchar()
+ if c == theNULL:
+ continue
+ if c == "\021":
+ continue
+ if c != IAC:
+ buf = buf + c
+ continue
+ c = self.rawq_getchar()
+ if c == IAC:
+ buf = buf + c
+ elif c in (DO, DONT):
+ opt = self.rawq_getchar()
+ self.msg('IAC %s %d', c == DO and 'DO' or 'DONT', ord(c))
+ self.sock.send(IAC + WONT + opt)
+ elif c in (WILL, WONT):
+ opt = self.rawq_getchar()
+ self.msg('IAC %s %d',
+ c == WILL and 'WILL' or 'WONT', ord(c))
+ else:
+ self.msg('IAC %s not recognized' % `c`)
+ except EOFError: # raised by self.rawq_getchar()
+ pass
+ self.cookedq = self.cookedq + buf
def rawq_getchar(self):
- """Get next char from raw queue.
-
- Block if no data is immediately available. Raise EOFError
- when connection is closed.
-
- """
- if not self.rawq:
- self.fill_rawq()
- if self.eof:
- raise EOFError
- c = self.rawq[self.irawq]
- self.irawq = self.irawq + 1
- if self.irawq >= len(self.rawq):
- self.rawq = ''
- self.irawq = 0
- return c
+ """Get next char from raw queue.
+
+ Block if no data is immediately available. Raise EOFError
+ when connection is closed.
+
+ """
+ if not self.rawq:
+ self.fill_rawq()
+ if self.eof:
+ raise EOFError
+ c = self.rawq[self.irawq]
+ self.irawq = self.irawq + 1
+ if self.irawq >= len(self.rawq):
+ self.rawq = ''
+ self.irawq = 0
+ return c
def fill_rawq(self):
- """Fill raw queue from exactly one recv() system call.
-
- Block if no data is immediately available. Set self.eof when
- connection is closed.
-
- """
- if self.irawq >= len(self.rawq):
- self.rawq = ''
- self.irawq = 0
- # The buffer size should be fairly small so as to avoid quadratic
- # behavior in process_rawq() above
- buf = self.sock.recv(50)
- self.msg("recv %s", `buf`)
- self.eof = (not buf)
- self.rawq = self.rawq + buf
+ """Fill raw queue from exactly one recv() system call.
+
+ Block if no data is immediately available. Set self.eof when
+ connection is closed.
+
+ """
+ if self.irawq >= len(self.rawq):
+ self.rawq = ''
+ self.irawq = 0
+ # The buffer size should be fairly small so as to avoid quadratic
+ # behavior in process_rawq() above
+ buf = self.sock.recv(50)
+ self.msg("recv %s", `buf`)
+ self.eof = (not buf)
+ self.rawq = self.rawq + buf
def sock_avail(self):
- """Test whether data is available on the socket."""
- return select.select([self], [], [], 0) == ([self], [], [])
+ """Test whether data is available on the socket."""
+ return select.select([self], [], [], 0) == ([self], [], [])
def interact(self):
- """Interaction function, emulates a very dumb telnet client."""
- while 1:
- rfd, wfd, xfd = select.select([self, sys.stdin], [], [])
- if self in rfd:
- try:
- text = self.read_eager()
- except EOFError:
- print '*** Connection closed by remote host ***'
- break
- if text:
- sys.stdout.write(text)
- sys.stdout.flush()
- if sys.stdin in rfd:
- line = sys.stdin.readline()
- if not line:
- break
- self.write(line)
+ """Interaction function, emulates a very dumb telnet client."""
+ while 1:
+ rfd, wfd, xfd = select.select([self, sys.stdin], [], [])
+ if self in rfd:
+ try:
+ text = self.read_eager()
+ except EOFError:
+ print '*** Connection closed by remote host ***'
+ break
+ if text:
+ sys.stdout.write(text)
+ sys.stdout.flush()
+ if sys.stdin in rfd:
+ line = sys.stdin.readline()
+ if not line:
+ break
+ self.write(line)
def expect(self, list, timeout=None):
- """Read until one from a list of a regular expressions matches.
-
- The first argument is a list of regular expressions, either
- compiled (re.RegexObject instances) or uncompiled (strings).
- The optional second argument is a timeout, in seconds; default
- is no timeout.
-
- Return a tuple of three items: the index in the list of the
- first regular expression that matches; the match object
- returned; and the text read up till and including the match.
-
- If EOF is read and no text was read, raise EOFError.
- Otherwise, when nothing matches, return (-1, None, text) where
- text is the text received so far (may be the empty string if a
- timeout happened).
-
- If a regular expression ends with a greedy match (e.g. '.*')
- or if more than one expression can match the same input, the
- results are undeterministic, and may depend on the I/O timing.
-
- """
- re = None
- list = list[:]
- indices = range(len(list))
- for i in indices:
- if not hasattr(list[i], "search"):
- if not re: import re
- list[i] = re.compile(list[i])
- while 1:
- self.process_rawq()
- for i in indices:
- m = list[i].search(self.cookedq)
- if m:
- e = m.end()
- text = self.cookedq[:e]
- self.cookedq = self.cookedq[e:]
- return (i, m, text)
- if self.eof:
- break
- if timeout is not None:
- r, w, x = select.select([self.fileno()], [], [], timeout)
- if not r:
- break
- self.fill_rawq()
- text = self.read_very_lazy()
- if not text and self.eof:
- raise EOFError
- return (-1, None, text)
+ """Read until one from a list of a regular expressions matches.
+
+ The first argument is a list of regular expressions, either
+ compiled (re.RegexObject instances) or uncompiled (strings).
+ The optional second argument is a timeout, in seconds; default
+ is no timeout.
+
+ Return a tuple of three items: the index in the list of the
+ first regular expression that matches; the match object
+ returned; and the text read up till and including the match.
+
+ If EOF is read and no text was read, raise EOFError.
+ Otherwise, when nothing matches, return (-1, None, text) where
+ text is the text received so far (may be the empty string if a
+ timeout happened).
+
+ If a regular expression ends with a greedy match (e.g. '.*')
+ or if more than one expression can match the same input, the
+ results are undeterministic, and may depend on the I/O timing.
+
+ """
+ re = None
+ list = list[:]
+ indices = range(len(list))
+ for i in indices:
+ if not hasattr(list[i], "search"):
+ if not re: import re
+ list[i] = re.compile(list[i])
+ while 1:
+ self.process_rawq()
+ for i in indices:
+ m = list[i].search(self.cookedq)
+ if m:
+ e = m.end()
+ text = self.cookedq[:e]
+ self.cookedq = self.cookedq[e:]
+ return (i, m, text)
+ if self.eof:
+ break
+ if timeout is not None:
+ r, w, x = select.select([self.fileno()], [], [], timeout)
+ if not r:
+ break
+ self.fill_rawq()
+ text = self.read_very_lazy()
+ if not text and self.eof:
+ raise EOFError
+ return (-1, None, text)
def test():
"""
debuglevel = 0
while sys.argv[1:] and sys.argv[1] == '-d':
- debuglevel = debuglevel+1
- del sys.argv[1]
+ debuglevel = debuglevel+1
+ del sys.argv[1]
host = 'localhost'
if sys.argv[1:]:
- host = sys.argv[1]
+ host = sys.argv[1]
port = 0
if sys.argv[2:]:
- portstr = sys.argv[2]
- try:
- port = int(portstr)
- except ValueError:
- port = socket.getservbyname(portstr, 'tcp')
+ portstr = sys.argv[2]
+ try:
+ port = int(portstr)
+ except ValueError:
+ port = socket.getservbyname(portstr, 'tcp')
tn = Telnet()
tn.set_debuglevel(debuglevel)
tn.open(host, port)
def gettempdir():
global tempdir
if tempdir is not None:
- return tempdir
+ return tempdir
attempdirs = ['/usr/tmp', '/tmp', os.getcwd(), os.curdir]
if os.name == 'nt':
- attempdirs.insert(0, 'C:\\TEMP')
- attempdirs.insert(0, '\\TEMP')
+ attempdirs.insert(0, 'C:\\TEMP')
+ attempdirs.insert(0, '\\TEMP')
elif os.name == 'mac':
- import macfs, MACFS
- try:
- refnum, dirid = macfs.FindFolder(MACFS.kOnSystemDisk,
- MACFS.kTemporaryFolderType, 0)
- dirname = macfs.FSSpec((refnum, dirid, '')).as_pathname()
- attempdirs.insert(0, dirname)
- except macfs.error:
- pass
+ import macfs, MACFS
+ try:
+ refnum, dirid = macfs.FindFolder(MACFS.kOnSystemDisk,
+ MACFS.kTemporaryFolderType, 0)
+ dirname = macfs.FSSpec((refnum, dirid, '')).as_pathname()
+ attempdirs.insert(0, dirname)
+ except macfs.error:
+ pass
for envname in 'TMPDIR', 'TEMP', 'TMP':
- if os.environ.has_key(envname):
- attempdirs.insert(0, os.environ[envname])
+ if os.environ.has_key(envname):
+ attempdirs.insert(0, os.environ[envname])
testfile = gettempprefix() + 'test'
for dir in attempdirs:
- try:
- filename = os.path.join(dir, testfile)
- fp = open(filename, 'w')
- fp.write('blat')
- fp.close()
- os.unlink(filename)
- tempdir = dir
- break
- except IOError:
- pass
+ try:
+ filename = os.path.join(dir, testfile)
+ fp = open(filename, 'w')
+ fp.write('blat')
+ fp.close()
+ os.unlink(filename)
+ tempdir = dir
+ break
+ except IOError:
+ pass
if tempdir is None:
- msg = "Can't find a usable temporary directory amongst " + `attempdirs`
- raise IOError, msg
+ msg = "Can't find a usable temporary directory amongst " + `attempdirs`
+ raise IOError, msg
return tempdir
# Function to calculate a prefix of the filename to use
def gettempprefix():
- global template
- if template == None:
- if os.name == 'posix':
- template = '@' + `os.getpid()` + '.'
- elif os.name == 'nt':
- template = '~' + `os.getpid()` + '-'
- elif os.name == 'mac':
- template = 'Python-Tmp-'
- else:
- template = 'tmp' # XXX might choose a better one
- return template
+ global template
+ if template == None:
+ if os.name == 'posix':
+ template = '@' + `os.getpid()` + '.'
+ elif os.name == 'nt':
+ template = '~' + `os.getpid()` + '-'
+ elif os.name == 'mac':
+ template = 'Python-Tmp-'
+ else:
+ template = 'tmp' # XXX might choose a better one
+ return template
# Counter for generating unique names
# User-callable function to return a unique temporary file name
def mktemp(suffix=""):
- global counter
- dir = gettempdir()
- pre = gettempprefix()
- while 1:
- counter = counter + 1
- file = os.path.join(dir, pre + `counter` + suffix)
- if not os.path.exists(file):
- return file
+ global counter
+ dir = gettempdir()
+ pre = gettempprefix()
+ while 1:
+ counter = counter + 1
+ file = os.path.join(dir, pre + `counter` + suffix)
+ if not os.path.exists(file):
+ return file
class TemporaryFileWrapper:
no longer needed.
"""
def __init__(self, file, path):
- self.file = file
- self.path = path
+ self.file = file
+ self.path = path
def close(self):
- self.file.close()
- os.unlink(self.path)
+ self.file.close()
+ os.unlink(self.path)
def __del__(self):
- try: self.close()
- except: pass
+ try: self.close()
+ except: pass
def __getattr__(self, name):
- file = self.__dict__['file']
- a = getattr(file, name)
- setattr(self, name, a)
- return a
+ file = self.__dict__['file']
+ a = getattr(file, name)
+ setattr(self, name, a)
+ return a
def TemporaryFile(mode='w+b', bufsize=-1, suffix=""):
name = mktemp(suffix)
file = open(name, mode, bufsize)
try:
- os.unlink(name)
+ os.unlink(name)
except os.error:
- # Non-unix -- can't unlink file that's still open, use wrapper
- return TemporaryFileWrapper(file, name)
+ # Non-unix -- can't unlink file that's still open, use wrapper
+ return TemporaryFileWrapper(file, name)
else:
- return file
+ return file
tok_name = {}
for _name, _value in globals().items():
if type(_value) is type(0):
- tok_name[_value] = _name
+ tok_name[_value] = _name
def ISTERMINAL(x):
inFileName = args and args[0] or "Include/token.h"
outFileName = "Lib/token.py"
if len(args) > 1:
- outFileName = args[1]
+ outFileName = args[1]
try:
- fp = open(inFileName)
+ fp = open(inFileName)
except IOError, err:
- sys.stdout.write("I/O error: %s\n" % str(err))
- sys.exit(1)
+ sys.stdout.write("I/O error: %s\n" % str(err))
+ sys.exit(1)
lines = string.splitfields(fp.read(), "\n")
fp.close()
prog = re.compile(
- "#define[ \t][ \t]*([A-Z][A-Z_]*)[ \t][ \t]*([0-9][0-9]*)",
- re.IGNORECASE)
+ "#define[ \t][ \t]*([A-Z][A-Z_]*)[ \t][ \t]*([0-9][0-9]*)",
+ re.IGNORECASE)
tokens = {}
for line in lines:
- match = prog.match(line)
- if match:
- name, val = match.group(1, 2)
- val = string.atoi(val)
- tokens[val] = name # reverse so we can sort them...
+ match = prog.match(line)
+ if match:
+ name, val = match.group(1, 2)
+ val = string.atoi(val)
+ tokens[val] = name # reverse so we can sort them...
keys = tokens.keys()
keys.sort()
# load the output skeleton from the target:
try:
- fp = open(outFileName)
+ fp = open(outFileName)
except IOError, err:
- sys.stderr.write("I/O error: %s\n" % str(err))
- sys.exit(2)
+ sys.stderr.write("I/O error: %s\n" % str(err))
+ sys.exit(2)
format = string.splitfields(fp.read(), "\n")
fp.close()
try:
- start = format.index("#--start constants--") + 1
- end = format.index("#--end constants--")
+ start = format.index("#--start constants--") + 1
+ end = format.index("#--end constants--")
except ValueError:
- sys.stderr.write("target does not contain format markers")
- sys.exit(3)
+ sys.stderr.write("target does not contain format markers")
+ sys.exit(3)
lines = []
for val in keys:
- lines.append("%s = %d" % (tokens[val], val))
+ lines.append("%s = %d" % (tokens[val], val))
format[start:end] = lines
try:
- fp = open(outFileName, 'w')
+ fp = open(outFileName, 'w')
except IOError, err:
- sys.stderr.write("I/O error: %s\n" % str(err))
- sys.exit(4)
+ sys.stderr.write("I/O error: %s\n" % str(err))
+ sys.exit(4)
fp.write(string.joinfields(format, "\n"))
fp.close()
def _f(): pass
FunctionType = type(_f)
-LambdaType = type(lambda: None) # Same as FunctionType
+LambdaType = type(lambda: None) # Same as FunctionType
try:
CodeType = type(_f.func_code)
except:
class _C:
def _m(self): pass
ClassType = type(_C)
-UnboundMethodType = type(_C._m) # Same as MethodType
+UnboundMethodType = type(_C._m) # Same as MethodType
_x = _C()
InstanceType = type(_x)
MethodType = type(_x._m)
BuiltinFunctionType = type(len)
-BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
+BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
ModuleType = type(sys)
try:
- FileType = type(sys.stdin) # XXX what if it was assigned to?
+ FileType = type(sys.stdin) # XXX what if it was assigned to?
except:
pass
XRangeType = type(xrange(0))
raise TypeError
except TypeError:
try:
- tb = sys.exc_info()[2]
- TracebackType = type(tb)
- FrameType = type(tb.tb_frame)
+ tb = sys.exc_info()[2]
+ TracebackType = type(tb)
+ FrameType = type(tb.tb_frame)
except:
- pass
+ pass
tb = None; del tb
SliceType = type(slice(0))
EllipsisType = type(Ellipsis)
-del sys, _f, _C, _x # Not for export
+del sys, _f, _C, _x # Not for export
import os
-home = os.curdir # Default
+home = os.curdir # Default
if os.environ.has_key('HOME'):
home = os.environ['HOME']
-elif os.name == 'nt': # Contributed by Jeff Bauer
+elif os.name == 'nt': # Contributed by Jeff Bauer
if os.environ.has_key('HOMEPATH'):
- if os.environ.has_key('HOMEDRIVE'):
- home = os.environ['HOMEDRIVE'] + os.environ['HOMEPATH']
- else:
- home = os.environ['HOMEPATH']
+ if os.environ.has_key('HOMEDRIVE'):
+ home = os.environ['HOMEDRIVE'] + os.environ['HOMEPATH']
+ else:
+ home = os.environ['HOMEPATH']
pythonrc = os.path.join(home, ".pythonrc.py")
try:
# If in_file is a pathname open it and change defaults
#
if in_file == '-':
- in_file = sys.stdin
+ in_file = sys.stdin
elif type(in_file) == type(''):
- if name == None:
- name = os.path.basename(in_file)
- if mode == None:
- try:
- mode = os.stat(in_file)[0]
- except AttributeError:
- pass
- in_file = open(in_file, 'rb')
+ if name == None:
+ name = os.path.basename(in_file)
+ if mode == None:
+ try:
+ mode = os.stat(in_file)[0]
+ except AttributeError:
+ pass
+ in_file = open(in_file, 'rb')
#
# Open out_file if it is a pathname
#
if out_file == '-':
- out_file = sys.stdout
+ out_file = sys.stdout
elif type(out_file) == type(''):
- out_file = open(out_file, 'w')
+ out_file = open(out_file, 'w')
#
# Set defaults for name and mode
#
if name == None:
- name = '-'
+ name = '-'
if mode == None:
- mode = 0666
+ mode = 0666
#
# Write the data
#
out_file.write('begin %o %s\n' % ((mode&0777),name))
str = in_file.read(45)
while len(str) > 0:
- out_file.write(binascii.b2a_uu(str))
- str = in_file.read(45)
+ out_file.write(binascii.b2a_uu(str))
+ str = in_file.read(45)
out_file.write(' \nend\n')
# Open the input file, if needed.
#
if in_file == '-':
- in_file = sys.stdin
+ in_file = sys.stdin
elif type(in_file) == type(''):
- in_file = open(in_file)
+ in_file = open(in_file)
#
# Read until a begin is encountered or we've exhausted the file
#
while 1:
- hdr = in_file.readline()
- if not hdr:
- raise Error, 'No valid begin line found in input file'
- if hdr[:5] != 'begin':
- continue
- hdrfields = string.split(hdr)
- if len(hdrfields) == 3 and hdrfields[0] == 'begin':
- try:
- string.atoi(hdrfields[1], 8)
- break
- except ValueError:
- pass
+ hdr = in_file.readline()
+ if not hdr:
+ raise Error, 'No valid begin line found in input file'
+ if hdr[:5] != 'begin':
+ continue
+ hdrfields = string.split(hdr)
+ if len(hdrfields) == 3 and hdrfields[0] == 'begin':
+ try:
+ string.atoi(hdrfields[1], 8)
+ break
+ except ValueError:
+ pass
if out_file == None:
- out_file = hdrfields[2]
+ out_file = hdrfields[2]
if mode == None:
- mode = string.atoi(hdrfields[1], 8)
+ mode = string.atoi(hdrfields[1], 8)
#
# Open the output file
#
if out_file == '-':
- out_file = sys.stdout
+ out_file = sys.stdout
elif type(out_file) == type(''):
- fp = open(out_file, 'wb')
- try:
- os.path.chmod(out_file, mode)
- except AttributeError:
- pass
- out_file = fp
+ fp = open(out_file, 'wb')
+ try:
+ os.path.chmod(out_file, mode)
+ except AttributeError:
+ pass
+ out_file = fp
#
# Main decoding loop
#
str = in_file.readline()
while str and str != 'end\n':
- out_file.write(binascii.a2b_uu(str))
- str = in_file.readline()
+ out_file.write(binascii.a2b_uu(str))
+ str = in_file.readline()
if not str:
- raise Error, 'Truncated input file'
+ raise Error, 'Truncated input file'
def test():
"""uuencode/uudecode main program"""
output = sys.stdout
ok = 1
try:
- optlist, args = getopt.getopt(sys.argv[1:], 'dt')
+ optlist, args = getopt.getopt(sys.argv[1:], 'dt')
except getopt.error:
- ok = 0
+ ok = 0
if not ok or len(args) > 2:
- print 'Usage:', sys.argv[0], '[-d] [-t] [input [output]]'
- print ' -d: Decode (in stead of encode)'
- print ' -t: data is text, encoded format unix-compatible text'
- sys.exit(1)
-
+ print 'Usage:', sys.argv[0], '[-d] [-t] [input [output]]'
+ print ' -d: Decode (in stead of encode)'
+ print ' -t: data is text, encoded format unix-compatible text'
+ sys.exit(1)
+
for o, a in optlist:
- if o == '-d': dopt = 1
- if o == '-t': topt = 1
+ if o == '-d': dopt = 1
+ if o == '-t': topt = 1
if len(args) > 0:
- input = args[0]
+ input = args[0]
if len(args) > 1:
- output = args[1]
+ output = args[1]
if dopt:
- if topt:
- if type(output) == type(''):
- output = open(output, 'w')
- else:
- print sys.argv[0], ': cannot do -t to stdout'
- sys.exit(1)
- decode(input, output)
+ if topt:
+ if type(output) == type(''):
+ output = open(output, 'w')
+ else:
+ print sys.argv[0], ': cannot do -t to stdout'
+ sys.exit(1)
+ decode(input, output)
else:
- if topt:
- if type(input) == type(''):
- input = open(input, 'r')
- else:
- print sys.argv[0], ': cannot do -t from stdin'
- sys.exit(1)
- encode(input, output)
+ if topt:
+ if type(input) == type(''):
+ input = open(input, 'r')
+ else:
+ print sys.argv[0], ': cannot do -t from stdin'
+ sys.exit(1)
+ encode(input, output)
if __name__ == '__main__':
test()
# Check for dbm first -- this has a .pag and a .dir file
try:
- f = open(filename + ".pag", "rb")
- f.close()
- f = open(filename + ".dir", "rb")
- f.close()
- return "dbm"
+ f = open(filename + ".pag", "rb")
+ f.close()
+ f = open(filename + ".dir", "rb")
+ f.close()
+ return "dbm"
except IOError:
- pass
+ pass
# See if the file exists, return None if not
try:
- f = open(filename, "rb")
+ f = open(filename, "rb")
except IOError:
- return None
+ return None
# Read the first 4 bytes of the file -- the magic number
s = f.read(4)
# Return "" if not at least 4 bytes
if len(s) != 4:
- return ""
+ return ""
# Convert to 4-byte int in native byte order -- return "" if impossible
try:
- (magic,) = struct.unpack("=l", s)
+ (magic,) = struct.unpack("=l", s)
except struct.error:
- return ""
+ return ""
# Check for GNU dbm
if magic == 0x13579ace:
- return "gdbm"
+ return "gdbm"
# Check for BSD hash
if magic == 0x061561:
- return "dbhash"
+ return "dbhash"
# Unknown
return ""
"""
def __init__(self, msg):
- self.msg = msg
+ self.msg = msg
def __repr__(self):
- return repr(self.msg)
+ return repr(self.msg)
def __str__(self):
- return str(self.msg)
+ return str(self.msg)
class ConversionError(Error):
"""Pack various data representations into a buffer."""
def __init__(self):
- self.reset()
+ self.reset()
def reset(self):
- self.__buf = ''
+ self.__buf = ''
def get_buffer(self):
- return self.__buf
+ return self.__buf
# backwards compatibility
get_buf = get_buffer
def pack_uint(self, x):
- self.__buf = self.__buf + struct.pack('>L', x)
+ self.__buf = self.__buf + struct.pack('>L', x)
pack_int = pack_uint
pack_enum = pack_int
def pack_bool(self, x):
- if x: self.__buf = self.__buf + '\0\0\0\1'
- else: self.__buf = self.__buf + '\0\0\0\0'
+ if x: self.__buf = self.__buf + '\0\0\0\1'
+ else: self.__buf = self.__buf + '\0\0\0\0'
def pack_uhyper(self, x):
- self.pack_uint(x>>32 & 0xffffffffL)
- self.pack_uint(x & 0xffffffffL)
+ self.pack_uint(x>>32 & 0xffffffffL)
+ self.pack_uint(x & 0xffffffffL)
pack_hyper = pack_uhyper
def pack_float(self, x):
- try: self.__buf = self.__buf + struct.pack('>f', x)
- except struct.error, msg:
- raise ConversionError, msg
+ try: self.__buf = self.__buf + struct.pack('>f', x)
+ except struct.error, msg:
+ raise ConversionError, msg
def pack_double(self, x):
- try: self.__buf = self.__buf + struct.pack('>d', x)
- except struct.error, msg:
- raise ConversionError, msg
+ try: self.__buf = self.__buf + struct.pack('>d', x)
+ except struct.error, msg:
+ raise ConversionError, msg
def pack_fstring(self, n, s):
- if n < 0:
- raise ValueError, 'fstring size must be nonnegative'
- n = ((n+3)/4)*4
- data = s[:n]
- data = data + (n - len(data)) * '\0'
- self.__buf = self.__buf + data
+ if n < 0:
+ raise ValueError, 'fstring size must be nonnegative'
+ n = ((n+3)/4)*4
+ data = s[:n]
+ data = data + (n - len(data)) * '\0'
+ self.__buf = self.__buf + data
pack_fopaque = pack_fstring
def pack_string(self, s):
- n = len(s)
- self.pack_uint(n)
- self.pack_fstring(n, s)
+ n = len(s)
+ self.pack_uint(n)
+ self.pack_fstring(n, s)
pack_opaque = pack_string
pack_bytes = pack_string
def pack_list(self, list, pack_item):
- for item in list:
- self.pack_uint(1)
- pack_item(item)
- self.pack_uint(0)
+ for item in list:
+ self.pack_uint(1)
+ pack_item(item)
+ self.pack_uint(0)
def pack_farray(self, n, list, pack_item):
- if len(list) <> n:
- raise ValueError, 'wrong array size'
- for item in list:
- pack_item(item)
+ if len(list) <> n:
+ raise ValueError, 'wrong array size'
+ for item in list:
+ pack_item(item)
def pack_array(self, list, pack_item):
- n = len(list)
- self.pack_uint(n)
- self.pack_farray(n, list, pack_item)
+ n = len(list)
+ self.pack_uint(n)
+ self.pack_farray(n, list, pack_item)
\f
"""Unpacks various data representations from the given buffer."""
def __init__(self, data):
- self.reset(data)
+ self.reset(data)
def reset(self, data):
- self.__buf = data
- self.__pos = 0
+ self.__buf = data
+ self.__pos = 0
def get_position(self):
- return self.__pos
+ return self.__pos
def set_position(self, position):
- self.__pos = position
+ self.__pos = position
def get_buffer(self):
- return self.__buf
+ return self.__buf
def done(self):
- if self.__pos < len(self.__buf):
- raise Error('unextracted data remains')
+ if self.__pos < len(self.__buf):
+ raise Error('unextracted data remains')
def unpack_uint(self):
- i = self.__pos
- self.__pos = j = i+4
- data = self.__buf[i:j]
- if len(data) < 4:
- raise EOFError
- x = struct.unpack('>L', data)[0]
- try:
- return int(x)
- except OverflowError:
- return x
+ i = self.__pos
+ self.__pos = j = i+4
+ data = self.__buf[i:j]
+ if len(data) < 4:
+ raise EOFError
+ x = struct.unpack('>L', data)[0]
+ try:
+ return int(x)
+ except OverflowError:
+ return x
def unpack_int(self):
- i = self.__pos
- self.__pos = j = i+4
- data = self.__buf[i:j]
- if len(data) < 4:
- raise EOFError
- return struct.unpack('>l', data)[0]
+ i = self.__pos
+ self.__pos = j = i+4
+ data = self.__buf[i:j]
+ if len(data) < 4:
+ raise EOFError
+ return struct.unpack('>l', data)[0]
unpack_enum = unpack_int
unpack_bool = unpack_int
def unpack_uhyper(self):
- hi = self.unpack_uint()
- lo = self.unpack_uint()
- return long(hi)<<32 | lo
+ hi = self.unpack_uint()
+ lo = self.unpack_uint()
+ return long(hi)<<32 | lo
def unpack_hyper(self):
- x = self.unpack_uhyper()
- if x >= 0x8000000000000000L:
- x = x - 0x10000000000000000L
- return x
+ x = self.unpack_uhyper()
+ if x >= 0x8000000000000000L:
+ x = x - 0x10000000000000000L
+ return x
def unpack_float(self):
- i = self.__pos
- self.__pos = j = i+4
- data = self.__buf[i:j]
- if len(data) < 4:
- raise EOFError
- return struct.unpack('>f', data)[0]
+ i = self.__pos
+ self.__pos = j = i+4
+ data = self.__buf[i:j]
+ if len(data) < 4:
+ raise EOFError
+ return struct.unpack('>f', data)[0]
def unpack_double(self):
- i = self.__pos
- self.__pos = j = i+8
- data = self.__buf[i:j]
- if len(data) < 8:
- raise EOFError
- return struct.unpack('>d', data)[0]
+ i = self.__pos
+ self.__pos = j = i+8
+ data = self.__buf[i:j]
+ if len(data) < 8:
+ raise EOFError
+ return struct.unpack('>d', data)[0]
def unpack_fstring(self, n):
- if n < 0:
- raise ValueError, 'fstring size must be nonnegative'
- i = self.__pos
- j = i + (n+3)/4*4
- if j > len(self.__buf):
- raise EOFError
- self.__pos = j
- return self.__buf[i:i+n]
+ if n < 0:
+ raise ValueError, 'fstring size must be nonnegative'
+ i = self.__pos
+ j = i + (n+3)/4*4
+ if j > len(self.__buf):
+ raise EOFError
+ self.__pos = j
+ return self.__buf[i:i+n]
unpack_fopaque = unpack_fstring
def unpack_string(self):
- n = self.unpack_uint()
- return self.unpack_fstring(n)
+ n = self.unpack_uint()
+ return self.unpack_fstring(n)
unpack_opaque = unpack_string
unpack_bytes = unpack_string
def unpack_list(self, unpack_item):
- list = []
- while 1:
- x = self.unpack_uint()
- if x == 0: break
- if x <> 1:
- raise ConversionError, '0 or 1 expected, got ' + `x`
- item = unpack_item()
- list.append(item)
- return list
+ list = []
+ while 1:
+ x = self.unpack_uint()
+ if x == 0: break
+ if x <> 1:
+ raise ConversionError, '0 or 1 expected, got ' + `x`
+ item = unpack_item()
+ list.append(item)
+ return list
def unpack_farray(self, n, unpack_item):
- list = []
- for i in range(n):
- list.append(unpack_item())
- return list
+ list = []
+ for i in range(n):
+ list.append(unpack_item())
+ return list
def unpack_array(self, unpack_item):
- n = self.unpack_uint()
- return self.unpack_farray(n, unpack_item)
+ n = self.unpack_uint()
+ return self.unpack_farray(n, unpack_item)
\f
# test suite
def _test():
p = Packer()
packtest = [
- (p.pack_uint, (9,)),
- (p.pack_bool, (None,)),
- (p.pack_bool, ('hello',)),
- (p.pack_uhyper, (45L,)),
- (p.pack_float, (1.9,)),
- (p.pack_double, (1.9,)),
- (p.pack_string, ('hello world',)),
- (p.pack_list, (range(5), p.pack_uint)),
- (p.pack_array, (['what', 'is', 'hapnin', 'doctor'], p.pack_string)),
- ]
+ (p.pack_uint, (9,)),
+ (p.pack_bool, (None,)),
+ (p.pack_bool, ('hello',)),
+ (p.pack_uhyper, (45L,)),
+ (p.pack_float, (1.9,)),
+ (p.pack_double, (1.9,)),
+ (p.pack_string, ('hello world',)),
+ (p.pack_list, (range(5), p.pack_uint)),
+ (p.pack_array, (['what', 'is', 'hapnin', 'doctor'], p.pack_string)),
+ ]
succeedlist = [1] * len(packtest)
count = 0
for method, args in packtest:
- print 'pack test', count,
- try:
- apply(method, args)
- print 'succeeded'
- except ConversionError, var:
- print 'ConversionError:', var.msg
- succeedlist[count] = 0
- count = count + 1
+ print 'pack test', count,
+ try:
+ apply(method, args)
+ print 'succeeded'
+ except ConversionError, var:
+ print 'ConversionError:', var.msg
+ succeedlist[count] = 0
+ count = count + 1
data = p.get_buffer()
# now verify
up = Unpacker(data)
unpacktest = [
- (up.unpack_uint, (), lambda x: x == 9),
- (up.unpack_bool, (), lambda x: not x),
- (up.unpack_bool, (), lambda x: x),
- (up.unpack_uhyper, (), lambda x: x == 45L),
- (up.unpack_float, (), lambda x: 1.89 < x < 1.91),
- (up.unpack_double, (), lambda x: 1.89 < x < 1.91),
- (up.unpack_string, (), lambda x: x == 'hello world'),
- (up.unpack_list, (up.unpack_uint,), lambda x: x == range(5)),
- (up.unpack_array, (up.unpack_string,),
- lambda x: x == ['what', 'is', 'hapnin', 'doctor']),
- ]
+ (up.unpack_uint, (), lambda x: x == 9),
+ (up.unpack_bool, (), lambda x: not x),
+ (up.unpack_bool, (), lambda x: x),
+ (up.unpack_uhyper, (), lambda x: x == 45L),
+ (up.unpack_float, (), lambda x: 1.89 < x < 1.91),
+ (up.unpack_double, (), lambda x: 1.89 < x < 1.91),
+ (up.unpack_string, (), lambda x: x == 'hello world'),
+ (up.unpack_list, (up.unpack_uint,), lambda x: x == range(5)),
+ (up.unpack_array, (up.unpack_string,),
+ lambda x: x == ['what', 'is', 'hapnin', 'doctor']),
+ ]
count = 0
for method, args, pred in unpacktest:
- print 'unpack test', count,
- try:
- if succeedlist[count]:
- x = apply(method, args)
- print pred(x) and 'succeeded' or 'failed', ':', x
- else:
- print 'skipping'
- except ConversionError, var:
- print 'ConversionError:', var.msg
- count = count + 1
+ print 'unpack test', count,
+ try:
+ if succeedlist[count]:
+ x = apply(method, args)
+ print pred(x) and 'succeeded' or 'failed', ':', x
+ else:
+ print 'skipping'
+ except ConversionError, var:
+ print 'ConversionError:', var.msg
+ count = count + 1
\f
if __name__ == '__main__':
_Name = '[a-zA-Z_:][-a-zA-Z0-9._:]*'
interesting = re.compile('[&<]')
incomplete = re.compile('&(' + _Name + '|#[0-9]*|#x[0-9a-fA-F]*)?|'
- '<([a-zA-Z_:][^<>]*|'
- '/([a-zA-Z_:][^<>]*)?|'
- '![^<>]*|'
- r'\?[^<>]*)?')
+ '<([a-zA-Z_:][^<>]*|'
+ '/([a-zA-Z_:][^<>]*)?|'
+ '![^<>]*|'
+ r'\?[^<>]*)?')
ref = re.compile('&(' + _Name + '|#[0-9]+|#x[0-9a-fA-F]+);?')
entityref = re.compile('&(?P<name>' + _Name + ')[^-a-zA-Z0-9._:]')
# Interface -- initialize and reset this instance
def __init__(self, verbose=0):
- self.verbose = verbose
- self.reset()
+ self.verbose = verbose
+ self.reset()
# Interface -- reset this instance. Loses all unprocessed data
def reset(self):
- self.rawdata = ''
- self.stack = []
- self.nomoretags = 0
- self.literal = 0
- self.lineno = 1
- self.__at_start = 1
- self.__seen_doctype = None
- self.__seen_starttag = 0
+ self.rawdata = ''
+ self.stack = []
+ self.nomoretags = 0
+ self.literal = 0
+ self.lineno = 1
+ self.__at_start = 1
+ self.__seen_doctype = None
+ self.__seen_starttag = 0
# For derived classes only -- enter literal mode (CDATA) till EOF
def setnomoretags(self):
- self.nomoretags = self.literal = 1
+ self.nomoretags = self.literal = 1
# For derived classes only -- enter literal mode (CDATA)
def setliteral(self, *args):
- self.literal = 1
+ self.literal = 1
# Interface -- feed some data to the parser. Call this as
# often as you want, with as little or as much text as you
# want (may include '\n'). (This just saves the text, all the
# processing is done by goahead().)
def feed(self, data):
- self.rawdata = self.rawdata + data
- self.goahead(0)
+ self.rawdata = self.rawdata + data
+ self.goahead(0)
# Interface -- handle the remaining data
def close(self):
- self.goahead(1)
+ self.goahead(1)
# Interface -- translate references
def translate_references(self, data):
- newdata = []
- i = 0
- while 1:
- res = ref.search(data, i)
- if res is None:
- newdata.append(data[i:])
- return string.join(newdata, '')
- if data[res.end(0) - 1] != ';':
- self.syntax_error("`;' missing after entity/char reference")
- newdata.append(data[i:res.start(0)])
- str = res.group(1)
- if str[0] == '#':
- if str[1] == 'x':
- newdata.append(chr(string.atoi(str[2:], 16)))
- else:
- newdata.append(chr(string.atoi(str[1:])))
- else:
- try:
- newdata.append(self.entitydefs[str])
- except KeyError:
- # can't do it, so keep the entity ref in
- newdata.append('&' + str + ';')
- i = res.end(0)
+ newdata = []
+ i = 0
+ while 1:
+ res = ref.search(data, i)
+ if res is None:
+ newdata.append(data[i:])
+ return string.join(newdata, '')
+ if data[res.end(0) - 1] != ';':
+ self.syntax_error("`;' missing after entity/char reference")
+ newdata.append(data[i:res.start(0)])
+ str = res.group(1)
+ if str[0] == '#':
+ if str[1] == 'x':
+ newdata.append(chr(string.atoi(str[2:], 16)))
+ else:
+ newdata.append(chr(string.atoi(str[1:])))
+ else:
+ try:
+ newdata.append(self.entitydefs[str])
+ except KeyError:
+ # can't do it, so keep the entity ref in
+ newdata.append('&' + str + ';')
+ i = res.end(0)
# Internal -- handle data as far as reasonable. May leave state
# and data to be processed by a subsequent call. If 'end' is
# true, force handling all data as if followed by EOF marker.
def goahead(self, end):
- rawdata = self.rawdata
- i = 0
- n = len(rawdata)
- while i < n:
- if i > 0:
- self.__at_start = 0
- if self.nomoretags:
- data = rawdata[i:n]
- self.handle_data(data)
- self.lineno = self.lineno + string.count(data, '\n')
- i = n
- break
- res = interesting.search(rawdata, i)
- if res:
- j = res.start(0)
- else:
- j = n
- if i < j:
- self.__at_start = 0
- data = rawdata[i:j]
- self.handle_data(data)
- self.lineno = self.lineno + string.count(data, '\n')
- i = j
- if i == n: break
- if rawdata[i] == '<':
- if starttagopen.match(rawdata, i):
- if self.literal:
- data = rawdata[i]
- self.handle_data(data)
- self.lineno = self.lineno + string.count(data, '\n')
- i = i+1
- continue
- k = self.parse_starttag(i)
- if k < 0: break
- self.__seen_starttag = 1
- self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
- i = k
- continue
- if endtagopen.match(rawdata, i):
- k = self.parse_endtag(i)
- if k < 0: break
- self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
- i = k
- self.literal = 0
- continue
- if commentopen.match(rawdata, i):
- if self.literal:
- data = rawdata[i]
- self.handle_data(data)
- self.lineno = self.lineno + string.count(data, '\n')
- i = i+1
- continue
- k = self.parse_comment(i)
- if k < 0: break
- self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
- i = k
- continue
- if cdataopen.match(rawdata, i):
- k = self.parse_cdata(i)
- if k < 0: break
- self.lineno = self.lineno + string.count(rawdata[i:i], '\n')
- i = k
- continue
- res = procopen.match(rawdata, i)
- if res:
- k = self.parse_proc(i)
- if k < 0: break
- self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
- i = k
- continue
- res = doctype.match(rawdata, i)
- if res:
- if self.literal:
- data = rawdata[i]
- self.handle_data(data)
- self.lineno = self.lineno + string.count(data, '\n')
- i = i+1
- continue
- if self.__seen_doctype:
- self.syntax_error('multiple DOCTYPE elements')
- if self.__seen_starttag:
- self.syntax_error('DOCTYPE not at beginning of document')
- k = self.parse_doctype(res)
- if k < 0: break
- self.__seen_doctype = res.group('name')
- self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
- i = k
- continue
- res = special.match(rawdata, i)
- if res:
- if self.literal:
- data = rawdata[i]
- self.handle_data(data)
- self.lineno = self.lineno + string.count(data, '\n')
- i = i+1
- continue
- self.handle_special(res.group('special'))
- self.lineno = self.lineno + string.count(res.group(0), '\n')
- i = res.end(0)
- continue
- elif rawdata[i] == '&':
- res = charref.match(rawdata, i)
- if res is not None:
- i = res.end(0)
- if rawdata[i-1] != ';':
- self.syntax_error("`;' missing in charref")
- i = i-1
- self.handle_charref(res.group('char')[:-1])
- self.lineno = self.lineno + string.count(res.group(0), '\n')
- continue
- res = entityref.match(rawdata, i)
- if res is not None:
- i = res.end(0)
- if rawdata[i-1] != ';':
- self.syntax_error("`;' missing in entityref")
- i = i-1
- self.handle_entityref(res.group('name'))
- self.lineno = self.lineno + string.count(res.group(0), '\n')
- continue
- else:
- raise RuntimeError, 'neither < nor & ??'
- # We get here only if incomplete matches but
- # nothing else
- res = incomplete.match(rawdata, i)
- if not res:
- data = rawdata[i]
- self.handle_data(data)
- self.lineno = self.lineno + string.count(data, '\n')
- i = i+1
- continue
- j = res.end(0)
- if j == n:
- break # Really incomplete
- self.syntax_error("bogus `<' or `&'")
- data = res.group(0)
- self.handle_data(data)
- self.lineno = self.lineno + string.count(data, '\n')
- i = j
- # end while
- if end and i < n:
- data = rawdata[i:n]
- self.handle_data(data)
- self.lineno = self.lineno + string.count(data, '\n')
- i = n
- self.rawdata = rawdata[i:]
- if end:
- if self.stack:
- self.syntax_error('missing end tags')
- while self.stack:
- self.finish_endtag(self.stack[-1])
+ rawdata = self.rawdata
+ i = 0
+ n = len(rawdata)
+ while i < n:
+ if i > 0:
+ self.__at_start = 0
+ if self.nomoretags:
+ data = rawdata[i:n]
+ self.handle_data(data)
+ self.lineno = self.lineno + string.count(data, '\n')
+ i = n
+ break
+ res = interesting.search(rawdata, i)
+ if res:
+ j = res.start(0)
+ else:
+ j = n
+ if i < j:
+ self.__at_start = 0
+ data = rawdata[i:j]
+ self.handle_data(data)
+ self.lineno = self.lineno + string.count(data, '\n')
+ i = j
+ if i == n: break
+ if rawdata[i] == '<':
+ if starttagopen.match(rawdata, i):
+ if self.literal:
+ data = rawdata[i]
+ self.handle_data(data)
+ self.lineno = self.lineno + string.count(data, '\n')
+ i = i+1
+ continue
+ k = self.parse_starttag(i)
+ if k < 0: break
+ self.__seen_starttag = 1
+ self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
+ i = k
+ continue
+ if endtagopen.match(rawdata, i):
+ k = self.parse_endtag(i)
+ if k < 0: break
+ self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
+ i = k
+ self.literal = 0
+ continue
+ if commentopen.match(rawdata, i):
+ if self.literal:
+ data = rawdata[i]
+ self.handle_data(data)
+ self.lineno = self.lineno + string.count(data, '\n')
+ i = i+1
+ continue
+ k = self.parse_comment(i)
+ if k < 0: break
+ self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
+ i = k
+ continue
+ if cdataopen.match(rawdata, i):
+ k = self.parse_cdata(i)
+ if k < 0: break
+ self.lineno = self.lineno + string.count(rawdata[i:i], '\n')
+ i = k
+ continue
+ res = procopen.match(rawdata, i)
+ if res:
+ k = self.parse_proc(i)
+ if k < 0: break
+ self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
+ i = k
+ continue
+ res = doctype.match(rawdata, i)
+ if res:
+ if self.literal:
+ data = rawdata[i]
+ self.handle_data(data)
+ self.lineno = self.lineno + string.count(data, '\n')
+ i = i+1
+ continue
+ if self.__seen_doctype:
+ self.syntax_error('multiple DOCTYPE elements')
+ if self.__seen_starttag:
+ self.syntax_error('DOCTYPE not at beginning of document')
+ k = self.parse_doctype(res)
+ if k < 0: break
+ self.__seen_doctype = res.group('name')
+ self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
+ i = k
+ continue
+ res = special.match(rawdata, i)
+ if res:
+ if self.literal:
+ data = rawdata[i]
+ self.handle_data(data)
+ self.lineno = self.lineno + string.count(data, '\n')
+ i = i+1
+ continue
+ self.handle_special(res.group('special'))
+ self.lineno = self.lineno + string.count(res.group(0), '\n')
+ i = res.end(0)
+ continue
+ elif rawdata[i] == '&':
+ res = charref.match(rawdata, i)
+ if res is not None:
+ i = res.end(0)
+ if rawdata[i-1] != ';':
+ self.syntax_error("`;' missing in charref")
+ i = i-1
+ self.handle_charref(res.group('char')[:-1])
+ self.lineno = self.lineno + string.count(res.group(0), '\n')
+ continue
+ res = entityref.match(rawdata, i)
+ if res is not None:
+ i = res.end(0)
+ if rawdata[i-1] != ';':
+ self.syntax_error("`;' missing in entityref")
+ i = i-1
+ self.handle_entityref(res.group('name'))
+ self.lineno = self.lineno + string.count(res.group(0), '\n')
+ continue
+ else:
+ raise RuntimeError, 'neither < nor & ??'
+ # We get here only if incomplete matches but
+ # nothing else
+ res = incomplete.match(rawdata, i)
+ if not res:
+ data = rawdata[i]
+ self.handle_data(data)
+ self.lineno = self.lineno + string.count(data, '\n')
+ i = i+1
+ continue
+ j = res.end(0)
+ if j == n:
+ break # Really incomplete
+ self.syntax_error("bogus `<' or `&'")
+ data = res.group(0)
+ self.handle_data(data)
+ self.lineno = self.lineno + string.count(data, '\n')
+ i = j
+ # end while
+ if end and i < n:
+ data = rawdata[i:n]
+ self.handle_data(data)
+ self.lineno = self.lineno + string.count(data, '\n')
+ i = n
+ self.rawdata = rawdata[i:]
+ if end:
+ if self.stack:
+ self.syntax_error('missing end tags')
+ while self.stack:
+ self.finish_endtag(self.stack[-1])
# Internal -- parse comment, return length or -1 if not terminated
def parse_comment(self, i):
- rawdata = self.rawdata
- if rawdata[i:i+4] <> '<!--':
- raise RuntimeError, 'unexpected call to handle_comment'
- res = commentclose.search(rawdata, i+4)
- if not res:
- return -1
- # doubledash search will succeed because it's a subset of commentclose
- if doubledash.search(rawdata, i+4).start(0) < res.start(0):
- self.syntax_error("`--' inside comment")
- self.handle_comment(rawdata[i+4: res.start(0)])
- return res.end(0)
+ rawdata = self.rawdata
+ if rawdata[i:i+4] <> '<!--':
+ raise RuntimeError, 'unexpected call to handle_comment'
+ res = commentclose.search(rawdata, i+4)
+ if not res:
+ return -1
+ # doubledash search will succeed because it's a subset of commentclose
+ if doubledash.search(rawdata, i+4).start(0) < res.start(0):
+ self.syntax_error("`--' inside comment")
+ self.handle_comment(rawdata[i+4: res.start(0)])
+ return res.end(0)
# Internal -- handle DOCTYPE tag, return length or -1 if not terminated
def parse_doctype(self, res):
- rawdata = self.rawdata
- n = len(rawdata)
- name = res.group('name')
- j = k = res.end(0)
- level = 0
- while k < n:
- c = rawdata[k]
- if c == '<':
- level = level + 1
- elif c == '>':
- if level == 0:
- self.handle_doctype(name, rawdata[j:k])
- return k+1
- level = level - 1
- k = k+1
- return -1
+ rawdata = self.rawdata
+ n = len(rawdata)
+ name = res.group('name')
+ j = k = res.end(0)
+ level = 0
+ while k < n:
+ c = rawdata[k]
+ if c == '<':
+ level = level + 1
+ elif c == '>':
+ if level == 0:
+ self.handle_doctype(name, rawdata[j:k])
+ return k+1
+ level = level - 1
+ k = k+1
+ return -1
# Internal -- handle CDATA tag, return length or -1 if not terminated
def parse_cdata(self, i):
- rawdata = self.rawdata
- if rawdata[i:i+9] <> '<![CDATA[':
- raise RuntimeError, 'unexpected call to handle_cdata'
- res = cdataclose.search(rawdata, i+9)
- if not res:
- return -1
- self.handle_cdata(rawdata[i+9:res.start(0)])
- return res.end(0)
+ rawdata = self.rawdata
+ if rawdata[i:i+9] <> '<![CDATA[':
+ raise RuntimeError, 'unexpected call to handle_cdata'
+ res = cdataclose.search(rawdata, i+9)
+ if not res:
+ return -1
+ self.handle_cdata(rawdata[i+9:res.start(0)])
+ return res.end(0)
__xml_attributes = {'version': '1.0', 'standalone': 'no', 'encoding': None}
# Internal -- handle a processing instruction tag
def parse_proc(self, i):
- rawdata = self.rawdata
- end = procclose.search(rawdata, i)
- if not end:
- return -1
- j = end.start(0)
- res = tagfind.match(rawdata, i+2)
- if not res:
- raise RuntimeError, 'unexpected call to parse_proc'
- k = res.end(0)
- name = res.group(0)
- if name == 'xml':
- if self.__at_start:
- attrdict, k = self.parse_attributes('xml', k, j,
- self.__xml_attributes)
- if k != j:
- self.syntax_error('garbage at end of <?xml?>')
- if attrdict['version'] != '1.0':
- self.syntax_error('only XML version 1.0 supported')
- self.handle_xml(attrdict.get('encoding', None),
- attrdict['standalone'])
- return end.end(0)
- else:
- self.syntax_error("<?xml?> tag not at start of document")
- self.handle_proc(name, rawdata[k:j])
- return end.end(0)
+ rawdata = self.rawdata
+ end = procclose.search(rawdata, i)
+ if not end:
+ return -1
+ j = end.start(0)
+ res = tagfind.match(rawdata, i+2)
+ if not res:
+ raise RuntimeError, 'unexpected call to parse_proc'
+ k = res.end(0)
+ name = res.group(0)
+ if name == 'xml':
+ if self.__at_start:
+ attrdict, k = self.parse_attributes('xml', k, j,
+ self.__xml_attributes)
+ if k != j:
+ self.syntax_error('garbage at end of <?xml?>')
+ if attrdict['version'] != '1.0':
+ self.syntax_error('only XML version 1.0 supported')
+ self.handle_xml(attrdict.get('encoding', None),
+ attrdict['standalone'])
+ return end.end(0)
+ else:
+ self.syntax_error("<?xml?> tag not at start of document")
+ self.handle_proc(name, rawdata[k:j])
+ return end.end(0)
# Internal -- parse attributes between i and j
def parse_attributes(self, tag, k, j, attributes = None):
- rawdata = self.rawdata
- # Now parse the data between k and j into a tag and attrs
- attrdict = {}
- try:
- # convert attributes list to dictionary
- d = {}
- for a in attributes:
- d[a] = None
- attributes = d
- except TypeError:
- pass
- while k < j:
- res = attrfind.match(rawdata, k)
- if not res: break
- attrname, attrvalue = res.group('name', 'value')
- if attrvalue is None:
- self.syntax_error('no attribute value specified')
- attrvalue = attrname
- elif attrvalue[:1] == "'" == attrvalue[-1:] or \
- attrvalue[:1] == '"' == attrvalue[-1:]:
- attrvalue = attrvalue[1:-1]
- else:
- self.syntax_error('attribute value not quoted')
- if attributes is not None and not attributes.has_key(attrname):
- self.syntax_error('unknown attribute %s of element %s' %
- (attrname, tag))
- if attrdict.has_key(attrname):
- self.syntax_error('attribute specified twice')
- attrdict[attrname] = self.translate_references(attrvalue)
- k = res.end(0)
- if attributes is not None:
- # fill in with default attributes
- for key, val in attributes.items():
- if val is not None and not attrdict.has_key(key):
- attrdict[key] = val
- return attrdict, k
+ rawdata = self.rawdata
+ # Now parse the data between k and j into a tag and attrs
+ attrdict = {}
+ try:
+ # convert attributes list to dictionary
+ d = {}
+ for a in attributes:
+ d[a] = None
+ attributes = d
+ except TypeError:
+ pass
+ while k < j:
+ res = attrfind.match(rawdata, k)
+ if not res: break
+ attrname, attrvalue = res.group('name', 'value')
+ if attrvalue is None:
+ self.syntax_error('no attribute value specified')
+ attrvalue = attrname
+ elif attrvalue[:1] == "'" == attrvalue[-1:] or \
+ attrvalue[:1] == '"' == attrvalue[-1:]:
+ attrvalue = attrvalue[1:-1]
+ else:
+ self.syntax_error('attribute value not quoted')
+ if attributes is not None and not attributes.has_key(attrname):
+ self.syntax_error('unknown attribute %s of element %s' %
+ (attrname, tag))
+ if attrdict.has_key(attrname):
+ self.syntax_error('attribute specified twice')
+ attrdict[attrname] = self.translate_references(attrvalue)
+ k = res.end(0)
+ if attributes is not None:
+ # fill in with default attributes
+ for key, val in attributes.items():
+ if val is not None and not attrdict.has_key(key):
+ attrdict[key] = val
+ return attrdict, k
# Internal -- handle starttag, return length or -1 if not terminated
def parse_starttag(self, i):
- rawdata = self.rawdata
- # i points to start of tag
- end = endbracket.search(rawdata, i+1)
- if not end:
- return -1
- j = end.start(0)
- res = tagfind.match(rawdata, i+1)
- if not res:
- raise RuntimeError, 'unexpected call to parse_starttag'
- k = res.end(0)
- tag = res.group(0)
- if not self.__seen_starttag and self.__seen_doctype:
- if tag != self.__seen_doctype:
- self.syntax_error('starttag does not match DOCTYPE')
- if hasattr(self, tag + '_attributes'):
- attributes = getattr(self, tag + '_attributes')
- else:
- attributes = None
- attrdict, k = self.parse_attributes(tag, k, j, attributes)
- res = starttagend.match(rawdata, k)
- if not res:
- self.syntax_error('garbage in start tag')
- self.finish_starttag(tag, attrdict)
- if res and res.group('slash') == '/':
- self.finish_endtag(tag)
- return end.end(0)
+ rawdata = self.rawdata
+ # i points to start of tag
+ end = endbracket.search(rawdata, i+1)
+ if not end:
+ return -1
+ j = end.start(0)
+ res = tagfind.match(rawdata, i+1)
+ if not res:
+ raise RuntimeError, 'unexpected call to parse_starttag'
+ k = res.end(0)
+ tag = res.group(0)
+ if not self.__seen_starttag and self.__seen_doctype:
+ if tag != self.__seen_doctype:
+ self.syntax_error('starttag does not match DOCTYPE')
+ if hasattr(self, tag + '_attributes'):
+ attributes = getattr(self, tag + '_attributes')
+ else:
+ attributes = None
+ attrdict, k = self.parse_attributes(tag, k, j, attributes)
+ res = starttagend.match(rawdata, k)
+ if not res:
+ self.syntax_error('garbage in start tag')
+ self.finish_starttag(tag, attrdict)
+ if res and res.group('slash') == '/':
+ self.finish_endtag(tag)
+ return end.end(0)
# Internal -- parse endtag
def parse_endtag(self, i):
- rawdata = self.rawdata
- end = endbracket.search(rawdata, i+1)
- if not end:
- return -1
- res = tagfind.match(rawdata, i+2)
- if not res:
- self.syntax_error('no name specified in end tag')
- tag = ''
- k = i+2
- else:
- tag = res.group(0)
- k = res.end(0)
- if k != end.start(0):
- # check that there is only white space at end of tag
- res = space.match(rawdata, k)
- if res is None or res.end(0) != end.start(0):
- self.syntax_error('garbage in end tag')
- self.finish_endtag(tag)
- return end.end(0)
+ rawdata = self.rawdata
+ end = endbracket.search(rawdata, i+1)
+ if not end:
+ return -1
+ res = tagfind.match(rawdata, i+2)
+ if not res:
+ self.syntax_error('no name specified in end tag')
+ tag = ''
+ k = i+2
+ else:
+ tag = res.group(0)
+ k = res.end(0)
+ if k != end.start(0):
+ # check that there is only white space at end of tag
+ res = space.match(rawdata, k)
+ if res is None or res.end(0) != end.start(0):
+ self.syntax_error('garbage in end tag')
+ self.finish_endtag(tag)
+ return end.end(0)
# Internal -- finish processing of start tag
# Return -1 for unknown tag, 1 for balanced tag
def finish_starttag(self, tag, attrs):
- self.stack.append(tag)
- try:
- method = getattr(self, 'start_' + tag)
- except AttributeError:
- self.unknown_starttag(tag, attrs)
- return -1
- else:
- self.handle_starttag(tag, method, attrs)
- return 1
+ self.stack.append(tag)
+ try:
+ method = getattr(self, 'start_' + tag)
+ except AttributeError:
+ self.unknown_starttag(tag, attrs)
+ return -1
+ else:
+ self.handle_starttag(tag, method, attrs)
+ return 1
# Internal -- finish processing of end tag
def finish_endtag(self, tag):
- if not tag:
- self.syntax_error('name-less end tag')
- found = len(self.stack) - 1
- if found < 0:
- self.unknown_endtag(tag)
- return
- else:
- if tag not in self.stack:
- self.syntax_error('unopened end tag')
- try:
- method = getattr(self, 'end_' + tag)
- except AttributeError:
- self.unknown_endtag(tag)
- return
- found = len(self.stack)
- for i in range(found):
- if self.stack[i] == tag:
- found = i
- while len(self.stack) > found:
- if found < len(self.stack) - 1:
- self.syntax_error('missing close tag for %s' % self.stack[-1])
- tag = self.stack[-1]
- try:
- method = getattr(self, 'end_' + tag)
- except AttributeError:
- method = None
- if method:
- self.handle_endtag(tag, method)
- else:
- self.unknown_endtag(tag)
- del self.stack[-1]
+ if not tag:
+ self.syntax_error('name-less end tag')
+ found = len(self.stack) - 1
+ if found < 0:
+ self.unknown_endtag(tag)
+ return
+ else:
+ if tag not in self.stack:
+ self.syntax_error('unopened end tag')
+ try:
+ method = getattr(self, 'end_' + tag)
+ except AttributeError:
+ self.unknown_endtag(tag)
+ return
+ found = len(self.stack)
+ for i in range(found):
+ if self.stack[i] == tag:
+ found = i
+ while len(self.stack) > found:
+ if found < len(self.stack) - 1:
+ self.syntax_error('missing close tag for %s' % self.stack[-1])
+ tag = self.stack[-1]
+ try:
+ method = getattr(self, 'end_' + tag)
+ except AttributeError:
+ method = None
+ if method:
+ self.handle_endtag(tag, method)
+ else:
+ self.unknown_endtag(tag)
+ del self.stack[-1]
# Overridable -- handle xml processing instruction
def handle_xml(self, encoding, standalone):
- pass
+ pass
# Overridable -- handle DOCTYPE
def handle_doctype(self, tag, data):
- pass
+ pass
# Overridable -- handle start tag
def handle_starttag(self, tag, method, attrs):
- method(attrs)
+ method(attrs)
# Overridable -- handle end tag
def handle_endtag(self, tag, method):
- method()
+ method()
# Example -- handle character reference, no need to override
def handle_charref(self, name):
- try:
- if name[0] == 'x':
- n = string.atoi(name[1:], 16)
- else:
- n = string.atoi(name)
- except string.atoi_error:
- self.unknown_charref(name)
- return
- if not 0 <= n <= 255:
- self.unknown_charref(name)
- return
- self.handle_data(chr(n))
+ try:
+ if name[0] == 'x':
+ n = string.atoi(name[1:], 16)
+ else:
+ n = string.atoi(name)
+ except string.atoi_error:
+ self.unknown_charref(name)
+ return
+ if not 0 <= n <= 255:
+ self.unknown_charref(name)
+ return
+ self.handle_data(chr(n))
# Definition of entities -- derived classes may override
entitydefs = {'lt': '<', 'gt': '>', 'amp': '&', 'quot': '"', 'apos': "'"}
# Example -- handle entity reference, no need to override
def handle_entityref(self, name):
- table = self.entitydefs
- if table.has_key(name):
- self.handle_data(table[name])
- else:
- self.unknown_entityref(name)
- return
+ table = self.entitydefs
+ if table.has_key(name):
+ self.handle_data(table[name])
+ else:
+ self.unknown_entityref(name)
+ return
# Example -- handle data, should be overridden
def handle_data(self, data):
- pass
+ pass
# Example -- handle cdata, could be overridden
def handle_cdata(self, data):
- pass
+ pass
# Example -- handle comment, could be overridden
def handle_comment(self, data):
- pass
+ pass
# Example -- handle processing instructions, could be overridden
def handle_proc(self, name, data):
- pass
+ pass
# Example -- handle special instructions, could be overridden
def handle_special(self, data):
- pass
+ pass
# Example -- handle relatively harmless syntax errors, could be overridden
def syntax_error(self, message):
- raise RuntimeError, 'Syntax error at line %d: %s' % (self.lineno, message)
+ raise RuntimeError, 'Syntax error at line %d: %s' % (self.lineno, message)
# To be overridden -- handlers for unknown objects
def unknown_starttag(self, tag, attrs): pass
class TestXMLParser(XMLParser):
def __init__(self, verbose=0):
- self.testdata = ""
- XMLParser.__init__(self, verbose)
+ self.testdata = ""
+ XMLParser.__init__(self, verbose)
def handle_xml(self, encoding, standalone):
- self.flush()
- print 'xml: encoding =',encoding,'standalone =',standalone
+ self.flush()
+ print 'xml: encoding =',encoding,'standalone =',standalone
def handle_doctype(self, tag, data):
- self.flush()
- print 'DOCTYPE:',tag, `data`
+ self.flush()
+ print 'DOCTYPE:',tag, `data`
def handle_data(self, data):
- self.testdata = self.testdata + data
- if len(`self.testdata`) >= 70:
- self.flush()
+ self.testdata = self.testdata + data
+ if len(`self.testdata`) >= 70:
+ self.flush()
def flush(self):
- data = self.testdata
- if data:
- self.testdata = ""
- print 'data:', `data`
+ data = self.testdata
+ if data:
+ self.testdata = ""
+ print 'data:', `data`
def handle_cdata(self, data):
- self.flush()
- print 'cdata:', `data`
+ self.flush()
+ print 'cdata:', `data`
def handle_proc(self, name, data):
- self.flush()
- print 'processing:',name,`data`
+ self.flush()
+ print 'processing:',name,`data`
def handle_special(self, data):
- self.flush()
- print 'special:',`data`
+ self.flush()
+ print 'special:',`data`
def handle_comment(self, data):
- self.flush()
- r = `data`
- if len(r) > 68:
- r = r[:32] + '...' + r[-32:]
- print 'comment:', r
+ self.flush()
+ r = `data`
+ if len(r) > 68:
+ r = r[:32] + '...' + r[-32:]
+ print 'comment:', r
def syntax_error(self, message):
- print 'error at line %d:' % self.lineno, message
+ print 'error at line %d:' % self.lineno, message
def unknown_starttag(self, tag, attrs):
- self.flush()
- if not attrs:
- print 'start tag: <' + tag + '>'
- else:
- print 'start tag: <' + tag,
- for name, value in attrs.items():
- print name + '=' + '"' + value + '"',
- print '>'
+ self.flush()
+ if not attrs:
+ print 'start tag: <' + tag + '>'
+ else:
+ print 'start tag: <' + tag,
+ for name, value in attrs.items():
+ print name + '=' + '"' + value + '"',
+ print '>'
def unknown_endtag(self, tag):
- self.flush()
- print 'end tag: </' + tag + '>'
+ self.flush()
+ print 'end tag: </' + tag + '>'
def unknown_entityref(self, ref):
- self.flush()
- print '*** unknown entity ref: &' + ref + ';'
+ self.flush()
+ print '*** unknown entity ref: &' + ref + ';'
def unknown_charref(self, ref):
- self.flush()
- print '*** unknown char ref: &#' + ref + ';'
+ self.flush()
+ print '*** unknown char ref: &#' + ref + ';'
def close(self):
- XMLParser.close(self)
- self.flush()
+ XMLParser.close(self)
+ self.flush()
def test(args = None):
import sys
if not args:
- args = sys.argv[1:]
+ args = sys.argv[1:]
if args and args[0] == '-s':
- args = args[1:]
- klass = XMLParser
+ args = args[1:]
+ klass = XMLParser
else:
- klass = TestXMLParser
+ klass = TestXMLParser
if args:
- file = args[0]
+ file = args[0]
else:
- file = 'test.xml'
+ file = 'test.xml'
if file == '-':
- f = sys.stdin
+ f = sys.stdin
else:
- try:
- f = open(file, 'r')
- except IOError, msg:
- print file, ":", msg
- sys.exit(1)
+ try:
+ f = open(file, 'r')
+ except IOError, msg:
+ print file, ":", msg
+ sys.exit(1)
data = f.read()
if f is not sys.stdin:
- f.close()
+ f.close()
x = klass()
for c in data:
- x.feed(c)
+ x.feed(c)
x.close()