Commit 5c1f5bd5 authored by Guido van Rossum's avatar Guido van Rossum

Renamed dos_8x3 to dos-8x3.

parent d7500fcb
"""File-like objects that read/write an array buffer.
This implements (nearly) all stdio methods.
f = ArrayIO() # ready for writing
f = ArrayIO(buf) # ready for reading
f.close() # explicitly release resources held
flag = f.isatty() # always false
pos = f.tell() # get current position
f.seek(pos) # set current position
f.seek(pos, mode) # mode 0: absolute; 1: relative; 2: relative to EOF
buf = f.read() # read until EOF
buf = f.read(n) # read up to n bytes
buf = f.readline() # read until end of line ('\n') or EOF
list = f.readlines()# list of f.readline() results until EOF
f.write(buf) # write at current position
f.writelines(list) # for line in list: f.write(line)
f.getvalue() # return whole file's contents as a string
Notes:
- This is very similar to StringIO. StringIO is faster for reading,
but ArrayIO is faster for writing.
- ArrayIO uses an array object internally, but all its interfaces
accept and return strings.
- Using a real file is often faster (but less convenient).
- fileno() is left unimplemented so that code which uses it triggers
an exception early.
- Seeking far beyond EOF and then writing will insert real null
bytes that occupy space in the buffer.
- There's a simple test set (see end of this file).
"""
import string
from array import array
class ArrayIO:
def __init__(self, buf = ''):
self.buf = array('c', buf)
self.pos = 0
self.closed = 0
self.softspace = 0
def close(self):
if not self.closed:
self.closed = 1
del self.buf, self.pos
def isatty(self):
return 0
def seek(self, pos, mode = 0):
if mode == 1:
pos = pos + self.pos
elif mode == 2:
pos = pos + len(self.buf)
self.pos = max(0, pos)
def tell(self):
return self.pos
def read(self, n = -1):
if n < 0:
newpos = len(self.buf)
else:
newpos = min(self.pos+n, len(self.buf))
r = self.buf[self.pos:newpos].tostring()
self.pos = newpos
return r
def readline(self):
i = string.find(self.buf[self.pos:].tostring(), '\n')
if i < 0:
newpos = len(self.buf)
else:
newpos = self.pos+i+1
r = self.buf[self.pos:newpos].tostring()
self.pos = newpos
return r
def readlines(self):
lines = string.splitfields(self.read(), '\n')
if not lines:
return lines
for i in range(len(lines)-1):
lines[i] = lines[i] + '\n'
if not lines[-1]:
del lines[-1]
return lines
def write(self, s):
if not s: return
a = array('c', s)
n = self.pos - len(self.buf)
if n > 0:
self.buf[len(self.buf):] = array('c', '\0')*n
newpos = self.pos + len(a)
self.buf[self.pos:newpos] = a
self.pos = newpos
def writelines(self, list):
self.write(string.joinfields(list, ''))
def flush(self):
pass
def getvalue(self):
return self.buf.tostring()
# A little test suite
def test():
import sys
if sys.argv[1:]:
file = sys.argv[1]
else:
file = '/etc/passwd'
lines = open(file, 'r').readlines()
text = open(file, 'r').read()
f = ArrayIO()
for line in lines[:-2]:
f.write(line)
f.writelines(lines[-2:])
if f.getvalue() != text:
raise RuntimeError, 'write failed'
length = f.tell()
print 'File length =', length
f.seek(len(lines[0]))
f.write(lines[1])
f.seek(0)
print 'First line =', `f.readline()`
here = f.tell()
line = f.readline()
print 'Second line =', `line`
f.seek(-len(line), 1)
line2 = f.read(len(line))
if line != line2:
raise RuntimeError, 'bad result after seek back'
f.seek(len(line2), 1)
list = f.readlines()
line = list[-1]
f.seek(f.tell() - len(line))
line2 = f.read()
if line != line2:
raise RuntimeError, 'bad result after seek back from EOF'
print 'Read', len(list), 'more lines'
print 'File length =', f.tell()
if f.tell() != length:
raise RuntimeError, 'bad length'
f.close()
if __name__ == '__main__':
test()
"""Object-oriented interface to the parser module.
This module exports four classes which together provide an interface
to the parser module. Together, the three classes represent two ways
to create parsed representations of Python source and the two starting
data types (source text and tuple representations). Each class
provides interfaces which are identical other than the constructors.
The constructors are described in detail in the documentation for each
class and the remaining, shared portion of the interface is documented
below. Briefly, the classes provided are:
AST
Defines the primary interface to the AST objects and supports creation
from the tuple representation of the parse tree.
ExpressionAST
Supports creation of expression constructs from source text.
SuiteAST
Supports creation of statement suites from source text.
FileSuiteAST
Convenience subclass of the `SuiteAST' class; loads source text of the
suite from an external file.
Common Methods
--------------
Aside from the constructors, several methods are provided to allow
access to the various interpretations of the parse tree and to check
conditions of the construct represented by the parse tree.
ast()
Returns the corresponding `parser.ASTType' object.
code()
Returns the compiled code object.
filename()
Returns the name of the associated source file, if known.
isExpression()
Returns true value if parse tree represents an expression, or a false
value otherwise.
isSuite()
Returns true value if parse tree represents a suite of statements, or
a false value otherwise.
text()
Returns the source text, or None if not available.
tuple()
Returns the tuple representing the parse tree.
"""
__version__ = '$Revision$'
__copyright__ = """Copyright (c) 1995, 1996 by Fred L. Drake, Jr.
This software may be used and distributed freely for any purpose provided
that this notice is included unchanged on any and all copies. The author
does not warrant or guarantee this software in any way.
"""
class AST:
"""Base class for Abstract Syntax Tree objects.
Creates an Abstract Syntax Tree based on the tuple representation
of the parse tree. The parse tree can represent either an
expression or a suite; which will be recognized automatically.
This base class provides all of the query methods for subclass
objects defined in this module.
"""
import parser # import internally to avoid
_p = parser # namespace pollution at the
# top level
_text = None
_code = None
_ast = None
_type = 'unknown'
_tupl = None
def __init__(self, tuple):
"""Create an `AST' instance from a tuple-tree representation.
tuple
The tuple tree to convert.
The tuple-tree may represent either an expression or a suite; the
type will be determined automatically. Line number information may
optionally be present for any subset of the terminal tokens.
"""
if type(tuple) is not type(()):
raise TypeError, 'Base AST class requires tuple parameter.'
self._tupl = tuple
self._ast = self._p.tuple2ast(tuple)
self._type = (self._p.isexpr(self._ast) and 'expression') or 'suite'
def list(self, line_info = 0):
"""Returns a fresh list representing the parse tree.
line_info
If true, includes line number information for terminal tokens in
the output data structure,
"""
return self._p.ast2list(self._ast, line_info)
def tuple(self, line_info = 0):
"""Returns the tuple representing the parse tree.
line_info
If true, includes line number information for terminal tokens in
the output data structure,
"""
if self._tupl is None:
self._tupl = self._p.ast2tuple(self._ast, line_info)
return self._tupl
def code(self):
"""Returns the compiled code object.
The code object returned by this method may be passed to the
exec statement if `AST.isSuite()' is true or to the eval()
function if `AST.isExpression()' is true. All the usual rules
regarding execution of code objects apply.
"""
if not self._code:
self._code = self._p.compileast(self._ast)
return self._code
def ast(self):
"""Returns the corresponding `parser.ASTType' object.
"""
return self._ast
def filename(self):
"""Returns the name of the source file if known, or None.
"""
return None
def text(self):
"""Returns the source text, or None if not available.
If the instance is of class `AST', None is returned since no
source text is available. If of class `ExpressionAST' or
`SuiteAST', the source text passed to the constructor is
returned.
"""
return self._text
def isSuite(self):
"""Determine if `AST' instance represents a suite of statements.
"""
return self._type == 'suite'
def isExpression(self):
"""Determine if `AST' instance represents an expression.
"""
return self._type == 'expression'
class SuiteAST(AST):
"""Statement suite parse tree representation.
This subclass of the `AST' base class represents statement suites
parsed from the source text of a Python suite. If the source text
does not represent a parsable suite of statements, the appropriate
exception is raised by the parser.
"""
_type = 'suite'
def __init__(self, text):
"""Initialize a `SuiteAST' from source text.
text
Source text to parse.
"""
if type(text) is not type(''):
raise TypeError, 'SuiteAST requires source text parameter.'
self._text = text
self._ast = self._p.suite(text)
def isSuite(self):
return 1
def isExpression(self):
return 0
class FileSuiteAST(SuiteAST):
"""Representation of a python source file syntax tree.
This provides a convenience wrapper around the `SuiteAST' class to
load the source text from an external file.
"""
def __init__(self, fileName):
"""Initialize a `SuiteAST' from a source file.
fileName
Name of the external source file.
"""
self._fileName = fileName
SuiteAST.__init__(self, open(fileName).read())
def filename(self):
return self._fileName
class ExpressionAST(AST):
"""Expression parse tree representation.
This subclass of the `AST' base class represents expression
constructs parsed from the source text of a Python expression. If
the source text does not represent a parsable expression, the
appropriate exception is raised by the Python parser.
"""
_type = 'expression'
def __init__(self, text):
"""Initialize an expression AST from source text.
text
Source text to parse.
"""
if type(text) is not type(''):
raise TypeError, 'ExpressionAST requires source text parameter.'
self._text = text
self._ast = self._p.expr(text)
def isSuite(self):
return 0
def isExpression(self):
return 1
#
# end of file
This diff is collapsed.
"""Bastionification utility.
A bastion (for another object -- the 'original') is an object that has
the same methods as the original but does not give access to its
instance variables. Bastions have a number of uses, but the most
obvious one is to provide code executing in restricted mode with a
safe interface to an object implemented in unrestricted mode.
The bastionification routine has an optional second argument which is
a filter function. Only those methods for which the filter method
(called with the method name as argument) returns true are accessible.
The default filter method returns true unless the method name begins
with an underscore.
There are a number of possible implementations of bastions. We use a
'lazy' approach where the bastion's __getattr__() discipline does all
the work for a particular method the first time it is used. This is
usually fastest, especially if the user doesn't call all available
methods. The retrieved methods are stored as instance variables of
the bastion, so the overhead is only occurred on the first use of each
method.
Detail: the bastion class has a __repr__() discipline which includes
the repr() of the original object. This is precomputed when the
bastion is created.
"""
from types import MethodType
class BastionClass:
"""Helper class used by the Bastion() function.
You could subclass this and pass the subclass as the bastionclass
argument to the Bastion() function, as long as the constructor has
the same signature (a get() function and a name for the object).
"""
def __init__(self, get, name):
"""Constructor.
Arguments:
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
def __repr__(self):
"""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.
"""
return "<Bastion for %s>" % self._name_
def __getattr__(self, name):
"""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.
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
def Bastion(object, filter = lambda name: name[:1] != '_',
name=None, bastionclass=BastionClass):
"""Create a bastion for an object, using an optional filter.
See the Bastion module's documentation for background.
Arguments:
object - the original object
filter - a predicate that decides whether a function name is OK;
by default all names are OK that don't start with '_'
name - the name of the object; default repr(object)
bastionclass - class used to create the bastion; default BastionClass
"""
# Note: we define *two* ad-hoc functions here, get1 and get2.
# Both are intended to be called in the same way: get(name).
# It is clear that the real work (getting the attribute
# from the object and calling the filter) is done in get1.
# Why can't we pass get1 to the bastion? Because the user
# would be able to override the filter argument! With get2,
# overriding the default argument is no security loophole:
# all it does is call it.
# Also notice that we can't place the object and filter as
# instance variables on the bastion object itself, since
# 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
def get2(name, get1=get1):
"""Internal function for Bastion(). See source comments."""
return get1(name)
if name is None:
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
o = Original()
b = Bastion(o)
testcode = """if 1:
b.add(81)
b.add(18)
print "b.total() =", b.total()
try:
print "b.sum =", b.sum,
except:
print "inaccessible"
else:
print "accessible"
try:
print "b._add =", b._add,
except:
print "inaccessible"
else:
print "accessible"
try:
print "b._get_.func_defaults =", b._get_.func_defaults,
except:
print "inaccessible"
else:
print "accessible"
\n"""
exec testcode
print '='*20, "Using rexec:", '='*20
import rexec
r = rexec.RExec()
m = r.add_module('__main__')
m.b = b
r.r_exec(testcode)
if __name__ == '__main__':
_test()
"""CGI-savvy HTTP Server.
This module builds on SimpleHTTPServer by implementing GET and POST
requests to cgi-bin scripts.
"""
__version__ = "0.3"
import os
import sys
import time
import socket
import string
import urllib
import BaseHTTPServer
import SimpleHTTPServer
class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
"""Complete HTTP server with GET, HEAD and POST commands.
GET and HEAD also support running CGI scripts.
The POST command is *only* implemented for CGI scripts.
"""
def do_POST(self):
"""Serve a POST request.
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")
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)
def is_cgi(self):
"""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.
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
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
import regsub
decoded_query = regsub.gsub('+', ' ', 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
def nobody_uid():
"""Internal routine to get nobody's uid"""
global nobody
if nobody:
return nobody
import pwd
try:
nobody = pwd.getpwnam('nobody')[2]
except pwd.error:
nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
return nobody
def executable(path):
"""Test for executable file."""
try:
st = os.stat(path)
except os.error:
return 0
return st[0] & 0111 != 0
def test(HandlerClass = CGIHTTPRequestHandler,
ServerClass = BaseHTTPServer.HTTPServer):
SimpleHTTPServer.test(HandlerClass, ServerClass)
if __name__ == '__main__':
test()
# Routines to force "compilation" of all .py files in a directory
# tree or on sys.path. By default recursion is pruned at a depth of
# 10 and the current directory, if it occurs in sys.path, is skipped.
# When called as a script, compiles argument directories, or sys.path
# if no arguments.
# After a similar module by Sjoerd Mullender.
import os
import sys
import py_compile
def compile_dir(dir, maxlevels = 10):
print 'Listing', dir, '...'
try:
names = os.listdir(dir)
except os.error:
print "Can't list", dir
names = []
names.sort()
for name in names:
fullname = os.path.join(dir, name)
if os.path.isfile(fullname):
head, tail = name[:-3], name[-3:]
if tail == '.py':
print 'Compiling', fullname, '...'
try:
py_compile.compile(fullname)
except KeyboardInterrupt:
del names[:]
print '\n[interrupt]'
break
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)
def compile_path(skip_curdir = 1):
for dir in sys.path:
if (not dir or dir == os.curdir) and skip_curdir:
print 'Skipping current directory'
else:
compile_dir(dir, 0)
def main():
import getopt
try:
opts, args = getopt.getopt(sys.argv[1:], 'l')
except getopt.error, msg:
print msg
print "usage: compileall [-l] [directory ...]"
print "-l: don't recurse down"
print "if no arguments, -l sys.path is assumed"
maxlevels = 10
for o, a in opts:
if o == '-l': maxlevels = 0
if args:
for dir in sys.argv[1:]:
compile_dir(dir, maxlevels)
else:
compile_path()
if __name__ == '__main__':
main()
# Complex numbers
# ---------------
# This module represents complex numbers as instances of the class Complex.
# A Complex instance z has two data attribues, z.re (the real part) and z.im
# (the imaginary part). In fact, z.re and z.im can have any value -- all
# arithmetic operators work regardless of the type of z.re and z.im (as long
# as they support numerical operations).
#
# The following functions exist (Complex is actually a class):
# Complex([re [,im]) -> creates a complex number from a real and an imaginary part
# IsComplex(z) -> true iff z is a complex number (== has .re and .im attributes)
# Polar([r [,phi [,fullcircle]]]) ->
# the complex number z for which r == z.radius() and phi == z.angle(fullcircle)
# (r and phi default to 0)
#
# Complex numbers have the following methods:
# z.abs() -> absolute value of z
# z.radius() == z.abs()
# z.angle([fullcircle]) -> angle from positive X axis; fullcircle gives units
# z.phi([fullcircle]) == z.angle(fullcircle)
#
# These standard functions and unary operators accept complex arguments:
# abs(z)
# -z
# +z
# not z
# repr(z) == `z`
# str(z)
# hash(z) -> a combination of hash(z.re) and hash(z.im) such that if z.im is zero
# the result equals hash(z.re)
# Note that hex(z) and oct(z) are not defined.
#
# These conversions accept complex arguments only if their imaginary part is zero:
# int(z)
# long(z)
# float(z)
#
# The following operators accept two complex numbers, or one complex number
# and one real number (int, long or float):
# z1 + z2
# z1 - z2
# z1 * z2
# z1 / z2
# pow(z1, z2)
# cmp(z1, z2)
# Note that z1 % z2 and divmod(z1, z2) are not defined,
# nor are shift and mask operations.
#
# The standard module math does not support complex numbers.
# (I suppose it would be easy to implement a cmath module.)
#
# Idea:
# add a class Polar(r, phi) and mixed-mode arithmetic which
# chooses the most appropriate type for the result:
# Complex for +,-,cmp
# Polar for *,/,pow
import types, math
if not hasattr(math, 'hypot'):
def hypot(x, y):
# XXX I know there's a way to compute this without possibly causing
# overflow, but I can't remember what it is right now...
return math.sqrt(x*x + y*y)
math.hypot = hypot
twopi = math.pi*2.0
halfpi = math.pi/2.0
def IsComplex(obj):
return hasattr(obj, 're') and hasattr(obj, 'im')
def Polar(r = 0, phi = 0, fullcircle = twopi):
phi = phi * (twopi / fullcircle)
return Complex(math.cos(phi)*r, math.sin(phi)*r)
class Complex:
def __init__(self, re=0, im=0):
if IsComplex(re):
im = im + re.im
re = re.re
if IsComplex(im):
re = re - im.im
im = im.re
self.re = re
self.im = im
def __setattr__(self, name, value):
if hasattr(self, name):
raise TypeError, "Complex numbers have set-once attributes"
self.__dict__[name] = value
def __repr__(self):
if not self.im:
return 'Complex(%s)' % `self.re`
else:
return 'Complex(%s, %s)' % (`self.re`, `self.im`)
def __str__(self):
if not self.im:
return `self.re`
else:
return 'Complex(%s, %s)' % (`self.re`, `self.im`)
def __coerce__(self, other):
if IsComplex(other):
return self, other
return self, Complex(other) # May fail
def __cmp__(self, other):
return cmp(self.re, other.re) or cmp(self.im, other.im)
def __hash__(self):
if not self.im: return hash(self.re)
mod = sys.maxint + 1L
return int((hash(self.re) + 2L*hash(self.im) + mod) % (2L*mod) - mod)
def __neg__(self):
return Complex(-self.re, -self.im)
def __pos__(self):
return self
def __abs__(self):
return math.hypot(self.re, self.im)
##return math.sqrt(self.re*self.re + self.im*self.im)
def __int__(self):
if self.im:
raise ValueError, "can't convert Complex with nonzero im to int"
return int(self.re)
def __long__(self):
if self.im:
raise ValueError, "can't convert Complex with nonzero im to long"
return long(self.re)
def __float__(self):
if self.im:
raise ValueError, "can't convert Complex with nonzero im to float"
return float(self.re)
def __nonzero__(self):
return not (self.re == self.im == 0)
abs = radius = __abs__
def angle(self, fullcircle = twopi):
return (fullcircle/twopi) * ((halfpi - math.atan2(self.re, self.im)) % twopi)
phi = angle
def __add__(self, other):
return Complex(self.re + other.re, self.im + other.im)
__radd__ = __add__
def __sub__(self, other):
return Complex(self.re - other.re, self.im - other.im)
def __rsub__(self, other):
return Complex(other.re - self.re, other.im - self.im)
def __mul__(self, other):
return Complex(self.re*other.re - self.im*other.im,
self.re*other.im + self.im*other.re)
__rmul__ = __mul__
def __div__(self, other):
# Deviating from the general principle of not forcing re or im
# to be floats, we cast to float here, otherwise division
# of Complex numbers with integer re and im parts would use
# the (truncating) integer division
d = float(other.re*other.re + other.im*other.im)
if not d: raise ZeroDivisionError, 'Complex division'
return Complex((self.re*other.re + self.im*other.im) / d,
(self.im*other.re - self.re*other.im) / d)
def __rdiv__(self, other):
return other / self
def __pow__(self, n, z=None):
if z is not None:
raise TypeError, 'Complex does not support ternary pow()'
if IsComplex(n):
if n.im: raise TypeError, 'Complex to the Complex power'
n = n.re
r = pow(self.abs(), n)
phi = n*self.angle()
return Complex(math.cos(phi)*r, math.sin(phi)*r)
def __rpow__(self, base):
return pow(base, self)
# Everything below this point is part of the test suite
def checkop(expr, a, b, value, fuzz = 1e-6):
import sys
print ' ', a, 'and', b,
try:
result = eval(expr)
except:
result = sys.exc_type
print '->', result
if (type(result) == type('') or type(value) == type('')):
ok = result == value
else:
ok = abs(result - value) <= fuzz
if not ok:
print '!!\t!!\t!! should be', value, 'diff', abs(result - value)
def test():
testsuite = {
'a+b': [
(1, 10, 11),
(1, Complex(0,10), Complex(1,10)),
(Complex(0,10), 1, Complex(1,10)),
(Complex(0,10), Complex(1), Complex(1,10)),
(Complex(1), Complex(0,10), Complex(1,10)),
],
'a-b': [
(1, 10, -9),
(1, Complex(0,10), Complex(1,-10)),
(Complex(0,10), 1, Complex(-1,10)),
(Complex(0,10), Complex(1), Complex(-1,10)),
(Complex(1), Complex(0,10), Complex(1,-10)),
],
'a*b': [
(1, 10, 10),
(1, Complex(0,10), Complex(0, 10)),
(Complex(0,10), 1, Complex(0,10)),
(Complex(0,10), Complex(1), Complex(0,10)),
(Complex(1), Complex(0,10), Complex(0,10)),
],
'a/b': [
(1., 10, 0.1),
(1, Complex(0,10), Complex(0, -0.1)),
(Complex(0, 10), 1, Complex(0, 10)),
(Complex(0, 10), Complex(1), Complex(0, 10)),
(Complex(1), Complex(0,10), Complex(0, -0.1)),
],
'pow(a,b)': [
(1, 10, 1),
(1, Complex(0,10), 'TypeError'),
(Complex(0,10), 1, Complex(0,10)),
(Complex(0,10), Complex(1), Complex(0,10)),
(Complex(1), Complex(0,10), 'TypeError'),
(2, Complex(4,0), 16),
],
'cmp(a,b)': [
(1, 10, -1),
(1, Complex(0,10), 1),
(Complex(0,10), 1, -1),
(Complex(0,10), Complex(1), -1),
(Complex(1), Complex(0,10), 1),
],
}
exprs = testsuite.keys()
exprs.sort()
for expr in exprs:
print expr + ':'
t = (expr,)
for item in testsuite[expr]:
apply(checkop, t+item)
if __name__ == '__main__':
test()
This diff is collapsed.
# Gopher protocol client interface
import string
# Default selector, host and port
DEF_SELECTOR = '1/'
DEF_HOST = 'gopher.micro.umn.edu'
DEF_PORT = 70
# Recognized file types
A_TEXT = '0'
A_MENU = '1'
A_CSO = '2'
A_ERROR = '3'
A_MACBINHEX = '4'
A_PCBINHEX = '5'
A_UUENCODED = '6'
A_INDEX = '7'
A_TELNET = '8'
A_BINARY = '9'
A_DUPLICATE = '+'
A_SOUND = 's'
A_EVENT = 'e'
A_CALENDAR = 'c'
A_HTML = 'h'
A_TN3270 = 'T'
A_MIME = 'M'
A_IMAGE = 'I'
A_WHOIS = 'w'
A_QUERY = 'q'
A_GIF = 'g'
A_HTML = 'h' # HTML file
A_WWW = 'w' # WWW address
A_PLUS_IMAGE = ':'
A_PLUS_MOVIE = ';'
A_PLUS_SOUND = '<'
# Function mapping all file types to strings; unknown types become TYPE='x'
_names = dir()
_type_to_name_map = None
def type_to_name(gtype):
global _type_to_name_map
if not _type_to_name_map:
for name in _names:
if name[:2] == 'A_':
_type_to_name_map[eval(name)] = name[2:]
if _type_to_name_map.has_key(gtype):
return _type_to_name_map[gtype]
return 'TYPE=' + `gtype`
# Names for characters and strings
CRLF = '\r\n'
TAB = '\t'
# Send a selector to a given host and port, return a file with the reply
def send_selector(selector, host, port = 0):
import socket
import string
if not port:
i = string.find(host, ':')
if i >= 0:
host, port = host[:i], string.atoi(host[i+1:])
if not port:
port = DEF_PORT
elif type(port) == type(''):
port = string.atoi(port)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(host, port)
s.send(selector + CRLF)
s.shutdown(1)
return s.makefile('rb')
# Send a selector and a query string
def send_query(selector, query, host, port = 0):
return send_selector(selector + '\t' + query, host, port)
# The following functions interpret the data returned by the gopher
# server according to the expected type, e.g. textfile or directory
# Get a directory in the form of a list of entries
def get_directory(f):
import string
list = []
while 1:
line = f.readline()
if not line:
print '(Unexpected EOF from server)'
break
if line[-2:] == CRLF:
line = line[:-2]
elif line[-1:] in CRLF:
line = line[:-1]
if line == '.':
break
if not line:
print '(Empty line from server)'
continue
gtype = line[0]
parts = string.splitfields(line[1:], TAB)
if len(parts) < 4:
print '(Bad line from server:', `line`, ')'
continue
if len(parts) > 4:
if parts[4:] != ['+']:
print '(Extra info from server:', parts[4:], ')'
else:
parts.append('')
parts.insert(0, gtype)
list.append(parts)
return list
# Get a text file as a list of lines, with trailing CRLF stripped
def get_textfile(f):
list = []
get_alt_textfile(f, list.append)
return list
# Get a text file and pass each line to a function, with trailing CRLF stripped
def get_alt_textfile(f, func):
while 1:
line = f.readline()
if not line:
print '(Unexpected EOF from server)'
break
if line[-2:] == CRLF:
line = line[:-2]
elif line[-1:] in CRLF:
line = line[:-1]
if line == '.':
break
if line[:2] == '..':
line = line[1:]
func(line)
# Get a binary file as one solid data block
def get_binary(f):
data = f.read()
return data
# Get a binary file and pass each block to a function
def get_alt_binary(f, func, blocksize):
while 1:
data = f.read(blocksize)
if not data:
break
func(data)
# Trivial test program
def test():
import sys
import getopt
opts, args = getopt.getopt(sys.argv[1:], '')
selector = DEF_SELECTOR
type = selector[0]
host = DEF_HOST
port = DEF_PORT
if args:
host = args[0]
args = args[1:]
if args:
type = args[0]
args = args[1:]
if len(type) > 1:
type, selector = type[0], type
else:
selector = ''
if args:
selector = args[0]
args = args[1:]
query = ''
if args:
query = args[0]
args = args[1:]
if type == A_INDEX:
f = send_query(selector, query, host)
else:
f = send_selector(selector, host)
if type == A_TEXT:
list = get_textfile(f)
for item in list: print item
elif type in (A_MENU, A_INDEX):
list = get_directory(f)
for item in list: print item
else:
data = get_binary(f)
print 'binary data:', len(data), 'bytes:', `data[:100]`[:40]
# Run the test when run as script
if __name__ == '__main__':
test()
# Proposed entity definitions for HTML, taken from
# http://www.w3.org/hypertext/WWW/MarkUp/html-spec/html-spec_14.html
entitydefs = {
'lt': '<',
'gt': '>',
'amp': '&',
'quot': '"',
'nbsp': chr(160), # no-break space
'iexcl': chr(161), # inverted exclamation mark
'cent': chr(162), # cent sign
'pound': chr(163), # pound sterling sign
'curren': chr(164), # general currency sign
'yen': chr(165), # yen sign
'brvbar': chr(166), # broken (vertical) bar
'sect': chr(167), # section sign
'uml': chr(168), # umlaut (dieresis)
'copy': chr(169), # copyright sign
'ordf': chr(170), # ordinal indicator, feminine
'laquo': chr(171), # angle quotation mark, left
'not': chr(172), # not sign
'shy': chr(173), # soft hyphen
'reg': chr(174), # registered sign
'macr': chr(175), # macron
'deg': chr(176), # degree sign
'plusmn': chr(177), # plus-or-minus sign
'sup2': chr(178), # superscript two
'sup3': chr(179), # superscript three
'acute': chr(180), # acute accent
'micro': chr(181), # micro sign
'para': chr(182), # pilcrow (paragraph sign)
'middot': chr(183), # middle dot
'cedil': chr(184), # cedilla
'sup1': chr(185), # superscript one
'ordm': chr(186), # ordinal indicator, masculine
'raquo': chr(187), # angle quotation mark, right
'frac14': chr(188), # fraction one-quarter
'frac12': chr(189), # fraction one-half
'frac34': chr(190), # fraction three-quarters
'iquest': chr(191), # inverted question mark
'Agrave': chr(192), # capital A, grave accent
'Aacute': chr(193), # capital A, acute accent
'Acirc': chr(194), # capital A, circumflex accent
'Atilde': chr(195), # capital A, tilde
'Auml': chr(196), # capital A, dieresis or umlaut mark
'Aring': chr(197), # capital A, ring
'AElig': chr(198), # capital AE diphthong (ligature)
'Ccedil': chr(199), # capital C, cedilla
'Egrave': chr(200), # capital E, grave accent
'Eacute': chr(201), # capital E, acute accent
'Ecirc': chr(202), # capital E, circumflex accent
'Euml': chr(203), # capital E, dieresis or umlaut mark
'Igrave': chr(204), # capital I, grave accent
'Iacute': chr(205), # capital I, acute accent
'Icirc': chr(206), # capital I, circumflex accent
'Iuml': chr(207), # capital I, dieresis or umlaut mark
'ETH': chr(208), # capital Eth, Icelandic
'Ntilde': chr(209), # capital N, tilde
'Ograve': chr(210), # capital O, grave accent
'Oacute': chr(211), # capital O, acute accent
'Ocirc': chr(212), # capital O, circumflex accent
'Otilde': chr(213), # capital O, tilde
'Ouml': chr(214), # capital O, dieresis or umlaut mark
'times': chr(215), # multiply sign
'Oslash': chr(216), # capital O, slash
'Ugrave': chr(217), # capital U, grave accent
'Uacute': chr(218), # capital U, acute accent
'Ucirc': chr(219), # capital U, circumflex accent
'Uuml': chr(220), # capital U, dieresis or umlaut mark
'Yacute': chr(221), # capital Y, acute accent
'THORN': chr(222), # capital THORN, Icelandic
'szlig': chr(223), # small sharp s, German (sz ligature)
'agrave': chr(224), # small a, grave accent
'aacute': chr(225), # small a, acute accent
'acirc': chr(226), # small a, circumflex accent
'atilde': chr(227), # small a, tilde
'auml': chr(228), # small a, dieresis or umlaut mark
'aring': chr(229), # small a, ring
'aelig': chr(230), # small ae diphthong (ligature)
'ccedil': chr(231), # small c, cedilla
'egrave': chr(232), # small e, grave accent
'eacute': chr(233), # small e, acute accent
'ecirc': chr(234), # small e, circumflex accent
'euml': chr(235), # small e, dieresis or umlaut mark
'igrave': chr(236), # small i, grave accent
'iacute': chr(237), # small i, acute accent
'icirc': chr(238), # small i, circumflex accent
'iuml': chr(239), # small i, dieresis or umlaut mark
'eth': chr(240), # small eth, Icelandic
'ntilde': chr(241), # small n, tilde
'ograve': chr(242), # small o, grave accent
'oacute': chr(243), # small o, acute accent
'ocirc': chr(244), # small o, circumflex accent
'otilde': chr(245), # small o, tilde
'ouml': chr(246), # small o, dieresis or umlaut mark
'divide': chr(247), # divide sign
'oslash': chr(248), # small o, slash
'ugrave': chr(249), # small u, grave accent
'uacute': chr(250), # small u, acute accent
'ucirc': chr(251), # small u, circumflex accent
'uuml': chr(252), # small u, dieresis or umlaut mark
'yacute': chr(253), # small y, acute accent
'thorn': chr(254), # small thorn, Icelandic
'yuml': chr(255), # small y, dieresis or umlaut mark
}
# THIS IS OBSOLETE -- USE MODULE 'compileall' INSTEAD!
# Utility module to import all modules in the path, in the hope
# that this will update their ".pyc" files.
import os
import sys
# Sabotage 'gl' and 'stdwin' to prevent windows popping up...
for m in 'gl', 'stdwin', 'fl', 'fm':
sys.modules[m] = sys
exceptions = ['importall']
for dir in sys.path:
print 'Listing', dir
try:
names = os.listdir(dir)
except os.error:
print 'Can\'t list', dir
names = []
names.sort()
for name in names:
head, tail = name[:-3], name[-3:]
if tail == '.py' and head not in exceptions:
s = 'import ' + head
print s
try:
exec s + '\n'
except KeyboardInterrupt:
del names[:]
print '\n[interrupt]'
break
except:
print 'Sorry:', sys.exc_type + ':',
print sys.exc_value
# Cache lines from files.
# This is intended to read lines from modules imported -- hence if a filename
# is not found, it will look down the module search path for a file by
# that name.
import sys
import os
from stat import *
def getline(filename, lineno):
lines = getlines(filename)
if 1 <= lineno <= len(lines):
return lines[lineno-1]
else:
return ''
# The cache
cache = {} # The cache
# Clear the cache entirely
def clearcache():
global cache
cache = {}
# Get the lines for a file from the cache.
# Update the cache if it doesn't contain an entry for this file already.
def getlines(filename):
if cache.has_key(filename):
return cache[filename][2]
else:
return updatecache(filename)
# Discard cache entries that are out of date.
# (This is not checked upon each call!)
def checkcache():
for filename in cache.keys():
size, mtime, lines, fullname = cache[filename]
try:
stat = os.stat(fullname)
except os.error:
del cache[filename]
continue
if size <> stat[ST_SIZE] or mtime <> stat[ST_MTIME]:
del cache[filename]
# Update a cache entry and return its list of lines.
# If something's wrong, print a message, discard the cache entry,
# and return an empty list.
def updatecache(filename):
if cache.has_key(filename):
del cache[filename]
if not filename or filename[0] + filename[-1] == '<>':
return []
fullname = filename
try:
stat = os.stat(fullname)
except os.error, msg:
# Try looking through the module search path
basename = os.path.split(filename)[1]
for dirname in sys.path:
fullname = os.path.join(dirname, basename)
try:
stat = os.stat(fullname)
break
except os.error:
pass
else:
# No luck
## print '*** Cannot stat', filename, ':', msg
return []
try:
fp = open(fullname, 'r')
lines = fp.readlines()
fp.close()
except IOError, msg:
## print '*** Cannot open', fullname, ':', msg
return []
size, mtime = stat[ST_SIZE], stat[ST_MTIME]
cache[filename] = size, mtime, lines, fullname
return lines
"""Mac specific module for conversion between pathnames and URLs.
Do not import directly, use urllib instead."""
import string
import urllib
import os
def url2pathname(pathname):
"Convert /-delimited pathname to mac pathname"
#
# XXXX The .. handling should be fixed...
#
tp = urllib.splittype(pathname)[0]
if tp and tp <> 'file':
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 not components[0]:
# 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, ':')
def pathname2url(pathname):
"convert mac pathname to /-delimited pathname"
if '/' in pathname:
raise RuntimeError, "Cannot convert pathname containing slashes"
components = string.split(pathname, ':')
# Remove empty first and/or last component
if components[0] == '':
del components[0]
if components[-1] == '':
del components[-1]
# Replace empty string ('::') by .. (will result in '/../' later)
for i in range(len(components)):
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, '/')
else:
return string.join(components, '/')
def test():
for url in ["index.html",
"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)`
if __name__ == '__main__':
test()
# Various tools used by MIME-reading or MIME-writing programs.
import os
import rfc822
import string
import tempfile
# A derived class of rfc822.Message that knows about MIME headers and
# contains some hooks for decoding encoded and multipart messages.
class Message(rfc822.Message):
def __init__(self, fp, seekable = 1):
rfc822.Message.__init__(self, fp, seekable)
self.encodingheader = \
self.getheader('content-transfer-encoding')
self.typeheader = \
self.getheader('content-type')
self.parsetype()
self.parseplist()
def parsetype(self):
str = self.typeheader
if str == None:
str = 'text/plain'
if ';' in str:
i = string.index(str, ';')
self.plisttext = str[i:]
str = str[:i]
else:
self.plisttext = ''
fields = string.splitfields(str, '/')
for i in range(len(fields)):
fields[i] = string.lower(string.strip(fields[i]))
self.type = string.joinfields(fields, '/')
self.maintype = fields[0]
self.subtype = string.joinfields(fields[1:], '/')
def parseplist(self):
str = self.plisttext
self.plist = []
while str[:1] == ';':
str = str[1:]
if ';' in str:
# XXX Should parse quotes!
end = string.index(str, ';')
else:
end = len(str)
f = str[:end]
if '=' in f:
i = string.index(f, '=')
f = string.lower(string.strip(f[:i])) + \
'=' + string.strip(f[i+1:])
self.plist.append(string.strip(f))
str = str[end:]
def getplist(self):
return self.plist
def getparam(self, name):
name = string.lower(name) + '='
n = len(name)
for p in self.plist:
if p[:n] == name:
return rfc822.unquote(p[n:])
return None
def getparamnames(self):
result = []
for p in self.plist:
i = string.find(p, '=')
if i >= 0:
result.append(string.lower(p[:i]))
return result
def getencoding(self):
if self.encodingheader == None:
return '7bit'
return string.lower(self.encodingheader)
def gettype(self):
return self.type
def getmaintype(self):
return self.maintype
def getsubtype(self):
return self.subtype
# Utility functions
# -----------------
# Return a random string usable as a multipart boundary.
# The method used is so that it is *very* unlikely that the same
# string of characters will every occur again in the Universe,
# so the caller needn't check the data it is packing for the
# occurrence of the boundary.
#
# The boundary contains dots so you have to quote it in the header.
_prefix = None
def choose_boundary():
global _prefix
import time
import rand
if _prefix == None:
import socket
import os
hostid = socket.gethostbyname(socket.gethostname())
try:
uid = `os.getuid()`
except:
uid = '1'
try:
pid = `os.getpid()`
except:
pid = '1'
seed = `rand.rand()`
_prefix = hostid + '.' + uid + '.' + pid
timestamp = `int(time.time())`
seed = `rand.rand()`
return _prefix + '.' + timestamp + '.' + seed
# Subroutines for decoding some common content-transfer-types
def decode(input, output, encoding):
if encoding == 'base64':
import base64
return base64.decode(input, output)
if encoding == 'quoted-printable':
import quopri
return quopri.decode(input, output)
if encoding in ('uuencode', 'x-uuencode'):
import uu
return uu.decode(input, output)
if decodetab.has_key(encoding):
pipethrough(input, decodetab[encoding], output)
else:
raise ValueError, \
'unknown Content-Transfer-Encoding: %s' % encoding
def encode(input, output, encoding):
if encoding == 'base64':
import base64
return base64.encode(input, output)
if encoding == 'quoted-printable':
import quopri
return quopri.encode(input, output, 0)
if encoding in ('uuencode', 'x-uuencode'):
import uu
return uu.encode(input, output)
if encodetab.has_key(encoding):
pipethrough(input, encodetab[encoding], output)
else:
raise ValueError, \
'unknown Content-Transfer-Encoding: %s' % encoding
# The following is no longer used for standard encodings
# XXX This requires that uudecode and mmencode are in $PATH
uudecode_pipe = '''(
TEMP=/tmp/@uu.$$
sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
cat $TEMP
rm $TEMP
)'''
decodetab = {
'uuencode': uudecode_pipe,
'x-uuencode': uudecode_pipe,
'quoted-printable': 'mmencode -u -q',
'base64': 'mmencode -u -b',
}
encodetab = {
'x-uuencode': 'uuencode tempfile',
'uuencode': 'uuencode tempfile',
'quoted-printable': 'mmencode -q',
'base64': 'mmencode -b',
}
def pipeto(input, command):
pipe = os.popen(command, 'w')
copyliteral(input, pipe)
pipe.close()
def pipethrough(input, command, output):
tempname = tempfile.mktemp()
try:
temp = open(tempname, 'w')
except IOError:
print '*** Cannot create temp file', `tempname`
return
copyliteral(input, temp)
temp.close()
pipe = os.popen(command + ' <' + tempname, 'r')
copybinary(pipe, output)
pipe.close()
os.unlink(tempname)
def copyliteral(input, output):
while 1:
line = input.readline()
if not line: break
output.write(line)
def copybinary(input, output):
BUFSIZE = 8192
while 1:
line = input.read(BUFSIZE)
if not line: break
output.write(line)
"""Generic MIME writer.
Classes:
MimeWriter - the only thing here.
"""
import string
import mimetools
class MimeWriter:
"""Generic MIME writer.
Methods:
__init__()
addheader()
flushheaders()
startbody()
startmultipartbody()
nextpart()
lastpart()
A MIME writer is much more primitive than a MIME parser. It
doesn't seek around on the output file, and it doesn't use large
amounts of buffer space, so you have to write the parts in the
order they should occur on the output file. It does buffer the
headers you add, allowing you to rearrange their order.
General usage is:
f = <open the output file>
w = MimeWriter(f)
...call w.addheader(key, value) 0 or more times...
followed by either:
f = w.startbody(content_type)
...call f.write(data) for body data...
or:
w.startmultipartbody(subtype)
for each part:
subwriter = w.nextpart()
...use the subwriter's methods to create the subpart...
w.lastpart()
The subwriter is another MimeWriter instance, and should be
treated in the same way as the toplevel MimeWriter. This way,
writing recursive body parts is easy.
Warning: don't forget to call lastpart()!
XXX There should be more state so calls made in the wrong order
are detected.
Some special cases:
- startbody() just returns the file passed to the constructor;
but don't use this knowledge, as it may be changed.
- startmultipartbody() actually returns a file as well;
this can be used to write the initial 'if you can read this your
mailer is not MIME-aware' message.
- If you call flushheaders(), the headers accumulated so far are
written out (and forgotten); this is useful if you don't need a
body part at all, e.g. for a subpart of type message/rfc822
that's (mis)used to store some header-like information.
- Passing a keyword argument 'prefix=<flag>' to addheader(),
start*body() affects where the header is inserted; 0 means
append at the end, 1 means insert at the start; default is
append for addheader(), but insert for start*body(), which use
it to determine where the Content-Type header goes.
"""
def __init__(self, fp):
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)
def flushheaders(self):
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
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)
def nextpart(self):
self._fp.write("\n--" + self._boundary + "\n")
return self.__class__(self._fp)
def lastpart(self):
self._fp.write("\n--" + self._boundary + "--\n")
if __name__ == '__main__':
print "To test the MimeWriter module, run TestMimeWriter.py."
# A class that makes each part of a multipart message "feel" like an
# ordinary file, as long as you use fp.readline(). Allows recursive
# use, for nested multipart messages. Probably best used together
# with module mimetools.
#
# Suggested use:
#
# real_fp = open(...)
# fp = MultiFile(real_fp)
#
# "read some lines from fp"
# fp.push(separator)
# while 1:
# "read lines from fp until it returns an empty string" (A)
# if not fp.next(): break
# fp.pop()
# "read remaining lines from fp until it returns an empty string"
#
# The latter sequence may be used recursively at (A).
# It is also allowed to use multiple push()...pop() sequences.
# Note that if a nested multipart message is terminated by a separator
# for an outer message, this is not reported, even though it is really
# illegal input.
import sys
import string
err = sys.stderr.write
Error = 'multifile.Error'
class MultiFile:
#
def __init__(self, fp):
self.fp = fp
self.stack = [] # Grows down
self.level = 0
self.last = 0
self.start = self.fp.tell()
self.posstack = [] # Grows down
#
def tell(self):
if self.level > 0:
return self.lastpos
return self.fp.tell() - self.start
#
def seek(self, pos):
if not 0 <= pos <= self.tell() or \
self.level > 0 and pos > self.lastpos:
raise Error, 'bad MultiFile.seek() call'
self.fp.seek(pos + self.start)
self.level = 0
self.last = 0
#
def readline(self):
if self.level > 0: return ''
line = self.fp.readline()
if not line:
self.level = len(self.stack)
self.last = (self.level > 0)
if self.last:
err('*** Sudden EOF in MultiFile.readline()\n')
return ''
if line[:2] <> '--': return line
n = len(line)
k = n
while k > 0 and line[k-1] in string.whitespace: k = k-1
mark = line[2:k]
if mark[-2:] == '--': mark1 = mark[:-2]
else: mark1 = None
for i in range(len(self.stack)):
sep = self.stack[i]
if sep == mark:
self.last = 0
break
elif mark1 <> None and sep == mark1:
self.last = 1
break
else:
return line
# Get here after break out of loop
self.lastpos = self.tell() - len(line)
self.level = i+1
if self.level > 1:
err('*** Missing endmarker in MultiFile.readline()\n')
return ''
#
def readlines(self):
list = []
while 1:
line = self.readline()
if not line: break
list.append(line)
return list
#
def read(self): # Note: no size argument -- read until EOF only!
return string.joinfields(self.readlines(), '')
#
def next(self):
while self.readline(): pass
if self.level > 1 or self.last:
return 0
self.level = 0
self.last = 0
self.start = self.fp.tell()
return 1
#
def push(self, sep):
if self.level > 0:
raise Error, 'bad MultiFile.push() call'
self.stack.insert(0, sep)
self.posstack.insert(0, self.start)
self.start = self.fp.tell()
#
def pop(self):
if self.stack == []:
raise Error, 'bad MultiFile.pop() call'
if self.level <= 1:
self.last = 0
else:
abslastpos = self.lastpos + self.start
self.level = max(0, self.level - 1)
del self.stack[0]
self.start = self.posstack[0]
del self.posstack[0]
if self.level > 0:
self.lastpos = abslastpos - self.start
#
#
# nturl2path convert a NT pathname to a file URL and
# vice versa
def url2pathname(url):
""" Convert a URL to a DOS path...
///C|/foo/bar/spam.foo
becomes
C:\foo\bar\spam.foo
"""
import string
if not '|' in url:
# No drive specifier, just convert slashes
components = string.splitfields(url, '/')
return string.joinfields(components, '\\')
comp = string.splitfields(url, '|')
if len(comp) != 2 or comp[0][-1] not in string.letters:
error = 'Bad URL: ' + url
raise IOError, error
drive = string.upper(comp[0][-1])
components = string.splitfields(comp[1], '/')
path = drive + ':'
for comp in components:
if comp:
path = path + '\\' + comp
return path
def pathname2url(p):
""" Convert a DOS path name to a file url...
C:\foo\bar\spam.foo
becomes
///C|/foo/bar/spam.foo
"""
import string
if not ':' in p:
# No drive specifier, just convert slashes
components = string.splitfields(p, '\\')
return string.joinfields(components, '/')
comp = string.splitfields(p, ':')
if len(comp) != 2 or len(comp[0]) > 1:
error = 'Bad path: ' + p
raise IOError, error
drive = string.upper(comp[0])
components = string.splitfields(comp[1], '\\')
path = '///' + drive + '|'
for comp in components:
if comp:
path = path + '/' + comp
return path
This diff is collapsed.
#
# Start of posixfile.py
#
#
# Extended file operations
#
# f = posixfile.open(filename, [mode, [bufsize]])
# will create a new posixfile object
#
# f = posixfile.fileopen(fileobject)
# will create a posixfile object from a builtin file object
#
# f.file()
# will return the original builtin file object
#
# f.dup()
# 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
#
# f.flags(mode)
# 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
# (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
#
# 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:
#
# (character representing type of 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')
#
# note: - the '?' modifier prevents a region from being locked; it is
# query only
#
class _posixfile_:
states = ['open', 'closed']
#
# 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:])
def __del__(self):
self._file_.close()
#
# Initialization routines
#
def open(self, name, mode='r', bufsize=-1):
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
#
# New methods
#
def file(self):
return self._file_
def dup(self):
import posix
try: ignore = posix.fdopen
except: raise AttributeError, 'dup() method unavailable'
return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)
def dup2(self, fd):
import posix
try: ignore = posix.fdopen
except: raise AttributeError, 'dup() method unavailable'
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
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 sys, os
if sys.platform == 'freebsd2':
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)
flock = fcntl.fcntl(self._file_.fileno(), cmd, flock)
if '?' in how:
if sys.platform == 'freebsd2':
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
#
# Public routine to obtain a posixfile object
#
def open(name, mode='r', bufsize=-1):
return _posixfile_().open(name, mode, bufsize)
def fileopen(file):
return _posixfile_().fileopen(file)
#
# Constants
#
SEEK_SET = 0
SEEK_CUR = 1
SEEK_END = 2
#
# End of posixfile.py
#
# Module 'posixpath' -- common operations on Posix pathnames.
# Some of this can actually be useful on non-Posix systems too, e.g.
# for manipulation of the pathname component of URLs.
# The "os.path" name is an alias for this module on Posix systems;
# on other systems (e.g. Mac, Windows), os.path provides the same
# operations in a manner specific to that platform, and is an alias
# to another module (e.g. macpath, ntpath).
import os
import stat
# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac.
# On MS-DOS this may also turn slashes into backslashes; however, other
# normalizations (such as optimizing '../' away) are not allowed
# (another function should be defined to do that).
def normcase(s):
return s
# Return wheter a path is absolute.
# Trivial in Posix, harder on the Mac or MS-DOS.
def isabs(s):
return s[:1] == '/'
# Join pathnames.
# Ignore the previous parts if a part is absolute.
# Insert a '/' unless the first part is empty or already ends in '/'.
def join(a, *p):
path = a
for b in p:
if b[:1] == '/':
path = b
elif path == '' or path[-1:] == '/':
path = path + b
else:
path = path + '/' + b
return path
# Split a path in head (everything up to the last '/') and tail (the
# rest). If the path ends in '/', tail will be empty. If there is no
# '/' in the path, head will be empty.
# Trailing '/'es are stripped from head unless it is the root.
def split(p):
import string
i = string.rfind(p, '/') + 1
head, tail = p[:i], p[i:]
if head and head <> '/'*len(head):
while head[-1] == '/':
head = head[:-1]
return head, tail
# Split a path in root and extension.
# The extension is everything starting at the last dot in the last
# pathname component; the root is everything before that.
# It is always true that root + ext == p.
def splitext(p):
root, ext = '', ''
for c in p:
if c == '/':
root, ext = root + ext + c, ''
elif c == '.':
if ext:
root, ext = root + ext, c
else:
ext = c
elif ext:
ext = ext + c
else:
root = root + c
return root, ext
# Split a pathname into a drive specification and the rest of the
# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
def splitdrive(p):
return '', p
# Return the tail (basename) part of a path.
def basename(p):
return split(p)[1]
# Return the head (dirname) part of a path.
def dirname(p):
return split(p)[0]
# Return the longest prefix of all list elements.
def commonprefix(m):
if not m: return ''
prefix = m[0]
for item in m:
for i in range(len(prefix)):
if prefix[:i+1] <> item[:i+1]:
prefix = prefix[:i]
if i == 0: return ''
break
return prefix
# Is a path a symbolic link?
# This will always return false on systems where os.lstat doesn't exist.
def islink(path):
try:
st = os.lstat(path)
except (os.error, AttributeError):
return 0
return stat.S_ISLNK(st[stat.ST_MODE])
# Does a path exist?
# This is false for dangling symbolic links.
def exists(path):
try:
st = os.stat(path)
except os.error:
return 0
return 1
# Is a path a directory?
# This follows symbolic links, so both islink() and isdir() can be true
# for the same path.
def isdir(path):
try:
st = os.stat(path)
except os.error:
return 0
return stat.S_ISDIR(st[stat.ST_MODE])
# Is a path a regular file?
# This follows symbolic links, so both islink() and isfile() can be true
# for the same path.
def isfile(path):
try:
st = os.stat(path)
except os.error:
return 0
return stat.S_ISREG(st[stat.ST_MODE])
# Are two filenames really pointing to the same file?
def samefile(f1, f2):
s1 = os.stat(f1)
s2 = os.stat(f2)
return samestat(s1, s2)
# Are two open files really referencing the same file?
# (Not necessarily the same file descriptor!)
def sameopenfile(fp1, fp2):
s1 = os.fstat(fp1)
s2 = os.fstat(fp2)
return samestat(s1, s2)
# Are two stat buffers (obtained from stat, fstat or lstat)
# describing the same file?
def samestat(s1, s2):
return s1[stat.ST_INO] == s2[stat.ST_INO] and \
s1[stat.ST_DEV] == s2[stat.ST_DEV]
# Is a path a mount point?
# (Does this work for all UNIXes? Is it even guaranteed to work by Posix?)
def ismount(path):
try:
s1 = os.stat(path)
s2 = os.stat(join(path, '..'))
except os.error:
return 0 # It doesn't exist -- so not a mount point :-)
dev1 = s1[stat.ST_DEV]
dev2 = s2[stat.ST_DEV]
if dev1 != dev2:
return 1 # path/.. on a different device as path
ino1 = s1[stat.ST_INO]
ino2 = s2[stat.ST_INO]
if ino1 == ino2:
return 1 # path/.. is the same i-node as path
return 0
# Directory tree walk.
# For each directory under top (including top itself, but excluding
# '.' and '..'), func(arg, dirname, filenames) is called, where
# dirname is the name of the directory and filenames is the list
# files files (and subdirectories etc.) in the directory.
# The func may modify the filenames list, to implement a filter,
# or to impose a different order of visiting.
def walk(top, func, arg):
try:
names = os.listdir(top)
except os.error:
return
func(arg, top, names)
exceptions = ('.', '..')
for name in names:
if name not in exceptions:
name = join(top, name)
if isdir(name) and not islink(name):
walk(name, func, arg)
# Expand paths beginning with '~' or '~user'.
# '~' means $HOME; '~user' means that user's home directory.
# If the path doesn't begin with '~', or if the user or $HOME is unknown,
# the path is returned unchanged (leaving error reporting to whatever
# function is called with the expanded path as argument).
# See also module 'glob' for expansion of *, ? and [...] in pathnames.
# (A function should also be defined to do full *sh-style environment
# variable expansion.)
def expanduser(path):
if path[:1] <> '~':
return path
i, n = 1, len(path)
while i < n and path[i] <> '/':
i = i+1
if i == 1:
if not os.environ.has_key('HOME'):
return path
userhome = os.environ['HOME']
else:
import pwd
try:
pwent = pwd.getpwnam(path[1:i])
except KeyError:
return path
userhome = pwent[5]
if userhome[-1:] == '/': i = i+1
return userhome + path[i:]
# Expand paths containing shell variable substitutions.
# This expands the forms $variable and ${variable} only.
# Non-existant variables are left unchanged.
_varprog = None
def expandvars(path):
global _varprog
if '$' not in path:
return path
if not _varprog:
import regex
_varprog = regex.compile('$\([a-zA-Z0-9_]+\|{[^}]*}\)')
i = 0
while 1:
i = _varprog.search(path, i)
if i < 0:
break
name = _varprog.group(1)
j = i + len(_varprog.group(0))
if name[:1] == '{' and name[-1:] == '}':
name = name[1:-1]
if os.environ.has_key(name):
tail = path[j:]
path = path[:i] + os.environ[name]
i = len(path)
path = path + tail
else:
i = j
return path
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
# It should be understood that this may change the meaning of the path
# if it contains symbolic links!
def normpath(path):
import string
# Treat initial slashes specially
slashes = ''
while path[:1] == '/':
slashes = slashes + '/'
path = path[1:]
comps = string.splitfields(path, '/')
i = 0
while i < len(comps):
if comps[i] == '.':
del comps[i]
elif comps[i] == '..' and i > 0 and \
comps[i-1] not in ('', '..'):
del comps[i-1:i+1]
i = i-1
elif comps[i] == '' and i > 0 and comps[i-1] <> '':
del comps[i]
else:
i = i+1
# If the path is now empty, substitute '.'
if not comps and not slashes:
comps.append('.')
return slashes + string.joinfields(comps, '/')
# Routine to "compile" a .py file to a .pyc file.
# This has intimate knowledge of how Python/import.c does it.
# By Sjoerd Mullender (I forced him to write it :-).
import imp
MAGIC = imp.get_magic()
def wr_long(f, x):
f.write(chr( x & 0xff))
f.write(chr((x >> 8) & 0xff))
f.write(chr((x >> 16) & 0xff))
f.write(chr((x >> 24) & 0xff))
def compile(file, cfile = None):
import os, marshal, __builtin__
f = open(file)
codestring = f.read()
f.close()
timestamp = long(os.stat(file)[8])
codeobject = __builtin__.compile(codestring, file, 'exec')
if not cfile:
cfile = file + (__debug__ and 'c' or 'o')
fc = open(cfile, 'wb')
fc.write(MAGIC)
wr_long(fc, timestamp)
marshal.dump(codeobject, fc)
fc.close()
if os.name == 'mac':
import macfs
macfs.FSSpec(cfile).SetCreatorType('Pyth', 'PYC ')
macfs.FSSpec(file).SetCreatorType('Pyth', 'TEXT')
# A multi-producer, multi-consumer queue.
Empty = 'Queue.Empty' # Exception raised by get_nowait()
class Queue:
# Initialize a queue object with a given maximum size
# (If maxsize is <= 0, the maximum size is infinite)
def __init__(self, maxsize):
import thread
self._init(maxsize)
self.mutex = thread.allocate_lock()
self.esema = thread.allocate_lock()
self.esema.acquire_lock()
self.fsema = thread.allocate_lock()
# Get an approximation of the queue size (not reliable!)
def qsize(self):
self.mutex.acquire_lock()
n = self._qsize()
self.mutex.release_lock()
return n
# Check if the queue is empty (not reliable!)
def empty(self):
self.mutex.acquire_lock()
n = self._empty()
self.mutex.release_lock()
return n
# Check if the queue is full (not reliable!)
def full(self):
self.mutex.acquire_lock()
n = self._full()
self.mutex.release_lock()
return n
# Put a new item into the queue
def put(self, item):
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()
# Get an item from the queue,
# blocking if necessary until one is available
def get(self):
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):
locked = self.esema.acquire_lock(0)
self.mutex.acquire_lock()
if self._empty():
# The queue is empyt -- 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.
# Override these methods to implement other queue organizations
# (e.g. stack or priority queue).
# These will only be called with appropriate locks held
# Initialize the queue representation
def _init(self, maxsize):
self.maxsize = maxsize
self.queue = []
def _qsize(self):
return len(self.queue)
# Check wheter the queue is empty
def _empty(self):
return not self.queue
# Check whether the queue is full
def _full(self):
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)
# Get an item from the queue
def _get(self):
item = self.queue[0]
del self.queue[0]
return item
# These bits are passed to regex.set_syntax() to choose among
# alternative regexp syntaxes.
# 1 means plain parentheses serve as grouping, and backslash
# parentheses are needed for literal searching.
# 0 means backslash-parentheses are grouping, and plain parentheses
# are for literal searching.
RE_NO_BK_PARENS = 1
# 1 means plain | serves as the "or"-operator, and \| is a literal.
# 0 means \| serves as the "or"-operator, and | is a literal.
RE_NO_BK_VBAR = 2
# 0 means plain + or ? serves as an operator, and \+, \? are literals.
# 1 means \+, \? are operators and plain +, ? are literals.
RE_BK_PLUS_QM = 4
# 1 means | binds tighter than ^ or $.
# 0 means the contrary.
RE_TIGHT_VBAR = 8
# 1 means treat \n as an _OR operator
# 0 means treat it as a normal character
RE_NEWLINE_OR = 16
# 0 means that a special characters (such as *, ^, and $) always have
# their special meaning regardless of the surrounding context.
# 1 means that special characters may act as normal characters in some
# contexts. Specifically, this applies to:
# ^ - only special at the beginning, or after ( or |
# $ - only special at the end, or before ) or |
# *, +, ? - only special when not after the beginning, (, or |
RE_CONTEXT_INDEP_OPS = 32
# Now define combinations of bits for the standard possibilities.
RE_SYNTAX_AWK = (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS)
RE_SYNTAX_EGREP = (RE_SYNTAX_AWK | RE_NEWLINE_OR)
RE_SYNTAX_GREP = (RE_BK_PLUS_QM | RE_NEWLINE_OR)
RE_SYNTAX_EMACS = 0
# (Python's obsolete "regexp" module used a syntax similar to awk.)
# Regex test suite and benchmark suite v1.5a2
# Due to the use of r"aw" strings, this file will
# only work with Python 1.5 or higher.
# The 3 possible outcomes for each pattern
[SUCCEED, FAIL, SYNTAX_ERROR] = range(3)
# Benchmark suite (needs expansion)
#
# The benchmark suite does not test correctness, just speed. The
# first element of each tuple is the regex pattern; the second is a
# string to match it against. The benchmarking code will embed the
# second string inside several sizes of padding, to test how regex
# matching performs on large strings.
benchmarks = [
('Python', 'Python'), # Simple text literal
('.*Python', 'Python'), # Bad text literal
('.*Python.*', 'Python'), # Worse text literal
('.*\\(Python\\)', 'Python'), # Bad text literal with grouping
('(Python\\|Perl\\|Tcl', 'Perl'), # Alternation
('\\(Python\\|Perl\\|Tcl\\)', 'Perl'), # Grouped alternation
('\\(Python\\)\\1', 'PythonPython'), # Backreference
# ('\\([0a-z][a-z]*,\\)+', 'a5,b7,c9,'), # Disable the fastmap optimization
('\\([a-z][a-z0-9]*,\\)+', 'a5,b7,c9,') # A few sets
]
# Test suite (for verifying correctness)
#
# The test suite is a list of 5- or 3-tuples. The 5 parts of a
# complete tuple are:
# element 0: a string containing the pattern
# 1: the string to match against the pattern
# 2: the expected result (SUCCEED, FAIL, SYNTAX_ERROR)
# 3: a string that will be eval()'ed to produce a test string.
# This is an arbitrary Python expression; the available
# variables are "found" (the whole match), and "g1", "g2", ...
# up to "g10" contain the contents of each group, or the
# string 'None' if the group wasn't given a value.
# 4: The expected result of evaluating the expression.
# If the two don't match, an error is reported.
#
# If the regex isn't expected to work, the latter two elements can be omitted.
tests = [
('abc', 'abc', SUCCEED,
'found', 'abc'),
('abc', 'xbc', FAIL),
('abc', 'axc', FAIL),
('abc', 'abx', FAIL),
('abc', 'xabcy', SUCCEED,
'found', 'abc'),
('abc', 'ababc', SUCCEED,
'found', 'abc'),
('ab*c', 'abc', SUCCEED,
'found', 'abc'),
('ab*bc', 'abc', SUCCEED,
'found', 'abc'),
('ab*bc', 'abbc', SUCCEED,
'found', 'abbc'),
('ab*bc', 'abbbbc', SUCCEED,
'found', 'abbbbc'),
('ab+bc', 'abbc', SUCCEED,
'found', 'abbc'),
('ab+bc', 'abc', FAIL),
('ab+bc', 'abq', FAIL),
('ab+bc', 'abbbbc', SUCCEED,
'found', 'abbbbc'),
('ab?bc', 'abbc', SUCCEED,
'found', 'abbc'),
('ab?bc', 'abc', SUCCEED,
'found', 'abc'),
('ab?bc', 'abbbbc', FAIL),
('ab?c', 'abc', SUCCEED,
'found', 'abc'),
('^abc$', 'abc', SUCCEED,
'found', 'abc'),
('^abc$', 'abcc', FAIL),
('^abc', 'abcc', SUCCEED,
'found', 'abc'),
('^abc$', 'aabc', FAIL),
('abc$', 'aabc', SUCCEED,
'found', 'abc'),
('^', 'abc', SUCCEED,
'found+"-"', '-'),
('$', 'abc', SUCCEED,
'found+"-"', '-'),
('a.c', 'abc', SUCCEED,
'found', 'abc'),
('a.c', 'axc', SUCCEED,
'found', 'axc'),
('a.*c', 'axyzc', SUCCEED,
'found', 'axyzc'),
('a.*c', 'axyzd', FAIL),
('a[bc]d', 'abc', FAIL),
('a[bc]d', 'abd', SUCCEED,
'found', 'abd'),
('a[b-d]e', 'abd', FAIL),
('a[b-d]e', 'ace', SUCCEED,
'found', 'ace'),
('a[b-d]', 'aac', SUCCEED,
'found', 'ac'),
('a[-b]', 'a-', SUCCEED,
'found', 'a-'),
('a[b-]', 'a-', SUCCEED,
'found', 'a-'),
('a[]b', '-', SYNTAX_ERROR),
('a[', '-', SYNTAX_ERROR),
('a\\', '-', SYNTAX_ERROR),
('abc\\)', '-', SYNTAX_ERROR),
('\\(abc', '-', SYNTAX_ERROR),
('a]', 'a]', SUCCEED,
'found', 'a]'),
('a[]]b', 'a]b', SUCCEED,
'found', 'a]b'),
('a[^bc]d', 'aed', SUCCEED,
'found', 'aed'),
('a[^bc]d', 'abd', FAIL),
('a[^-b]c', 'adc', SUCCEED,
'found', 'adc'),
('a[^-b]c', 'a-c', FAIL),
('a[^]b]c', 'a]c', FAIL),
('a[^]b]c', 'adc', SUCCEED,
'found', 'adc'),
('\\ba\\b', 'a-', SUCCEED,
'"-"', '-'),
('\\ba\\b', '-a', SUCCEED,
'"-"', '-'),
('\\ba\\b', '-a-', SUCCEED,
'"-"', '-'),
('\\by\\b', 'xy', FAIL),
('\\by\\b', 'yz', FAIL),
('\\by\\b', 'xyz', FAIL),
('ab\\|cd', 'abc', SUCCEED,
'found', 'ab'),
('ab\\|cd', 'abcd', SUCCEED,
'found', 'ab'),
('\\(\\)ef', 'def', SUCCEED,
'found+"-"+g1', 'ef-'),
('$b', 'b', FAIL),
('a(b', 'a(b', SUCCEED,
'found+"-"+g1', 'a(b-None'),
('a(*b', 'ab', SUCCEED,
'found', 'ab'),
('a(*b', 'a((b', SUCCEED,
'found', 'a((b'),
('a\\\\b', 'a\\b', SUCCEED,
'found', 'a\\b'),
('\\(\\(a\\)\\)', 'abc', SUCCEED,
'found+"-"+g1+"-"+g2', 'a-a-a'),
('\\(a\\)b\\(c\\)', 'abc', SUCCEED,
'found+"-"+g1+"-"+g2', 'abc-a-c'),
('a+b+c', 'aabbabc', SUCCEED,
'found', 'abc'),
('\\(a+\\|b\\)*', 'ab', SUCCEED,
'found+"-"+g1', 'ab-b'),
('\\(a+\\|b\\)+', 'ab', SUCCEED,
'found+"-"+g1', 'ab-b'),
('\\(a+\\|b\\)?', 'ab', SUCCEED,
'found+"-"+g1', 'a-a'),
('\\)\\(', '-', SYNTAX_ERROR),
('[^ab]*', 'cde', SUCCEED,
'found', 'cde'),
('abc', '', FAIL),
('a*', '', SUCCEED,
'found', ''),
('a\\|b\\|c\\|d\\|e', 'e', SUCCEED,
'found', 'e'),
('\\(a\\|b\\|c\\|d\\|e\\)f', 'ef', SUCCEED,
'found+"-"+g1', 'ef-e'),
('abcd*efg', 'abcdefg', SUCCEED,
'found', 'abcdefg'),
('ab*', 'xabyabbbz', SUCCEED,
'found', 'ab'),
('ab*', 'xayabbbz', SUCCEED,
'found', 'a'),
('\\(ab\\|cd\\)e', 'abcde', SUCCEED,
'found+"-"+g1', 'cde-cd'),
('[abhgefdc]ij', 'hij', SUCCEED,
'found', 'hij'),
('^\\(ab\\|cd\\)e', 'abcde', FAIL,
'xg1y', 'xy'),
('\\(abc\\|\\)ef', 'abcdef', SUCCEED,
'found+"-"+g1', 'ef-'),
('\\(a\\|b\\)c*d', 'abcd', SUCCEED,
'found+"-"+g1', 'bcd-b'),
('\\(ab\\|ab*\\)bc', 'abc', SUCCEED,
'found+"-"+g1', 'abc-a'),
('a\\([bc]*\\)c*', 'abc', SUCCEED,
'found+"-"+g1', 'abc-bc'),
('a\\([bc]*\\)\\(c*d\\)', 'abcd', SUCCEED,
'found+"-"+g1+"-"+g2', 'abcd-bc-d'),
('a\\([bc]+\\)\\(c*d\\)', 'abcd', SUCCEED,
'found+"-"+g1+"-"+g2', 'abcd-bc-d'),
('a\\([bc]*\\)\\(c+d\\)', 'abcd', SUCCEED,
'found+"-"+g1+"-"+g2', 'abcd-b-cd'),
('a[bcd]*dcdcde', 'adcdcde', SUCCEED,
'found', 'adcdcde'),
('a[bcd]+dcdcde', 'adcdcde', FAIL),
('\\(ab\\|a\\)b*c', 'abc', SUCCEED,
'found+"-"+g1', 'abc-ab'),
('\\(\\(a\\)\\(b\\)c\\)\\(d\\)', 'abcd', SUCCEED,
'g1+"-"+g2+"-"+g3+"-"+g4', 'abc-a-b-d'),
('[a-zA-Z_][a-zA-Z0-9_]*', 'alpha', SUCCEED,
'found', 'alpha'),
('^a\\(bc+\\|b[eh]\\)g\\|.h$', 'abh', SUCCEED,
'found+"-"+g1', 'bh-None'),
('\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'effgz', SUCCEED,
'found+"-"+g1+"-"+g2', 'effgz-effgz-None'),
('\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'ij', SUCCEED,
'found+"-"+g1+"-"+g2', 'ij-ij-j'),
('\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'effg', FAIL),
('\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'bcdd', FAIL),
('\\(bc+d$\\|ef*g.\\|h?i\\(j\\|k\\)\\)', 'reffgz', SUCCEED,
'found+"-"+g1+"-"+g2', 'effgz-effgz-None'),
('\\(\\(\\(\\(\\(\\(\\(\\(\\(a\\)\\)\\)\\)\\)\\)\\)\\)\\)', 'a', SUCCEED,
'found', 'a'),
('multiple words of text', 'uh-uh', FAIL),
('multiple words', 'multiple words, yeah', SUCCEED,
'found', 'multiple words'),
('\\(.*\\)c\\(.*\\)', 'abcde', SUCCEED,
'found+"-"+g1+"-"+g2', 'abcde-ab-de'),
('(\\(.*\\), \\(.*\\))', '(a, b)', SUCCEED,
'g2+"-"+g1', 'b-a'),
('[k]', 'ab', FAIL),
('a[-]?c', 'ac', SUCCEED,
'found', 'ac'),
('\\(abc\\)\\1', 'abcabc', SUCCEED,
'g1', 'abc'),
('\\([a-c]*\\)\\1', 'abcabc', SUCCEED,
'g1', 'abc'),
('^\\(.+\\)?B', 'AB', SUCCEED,
'g1', 'A'),
('\\(a+\\).\\1$', 'aaaaa', SUCCEED,
'found+"-"+g1', 'aaaaa-aa'),
('^\\(a+\\).\\1$', 'aaaa', FAIL),
('\\(abc\\)\\1', 'abcabc', SUCCEED,
'found+"-"+g1', 'abcabc-abc'),
('\\([a-c]+\\)\\1', 'abcabc', SUCCEED,
'found+"-"+g1', 'abcabc-abc'),
('\\(a\\)\\1', 'aa', SUCCEED,
'found+"-"+g1', 'aa-a'),
('\\(a+\\)\\1', 'aa', SUCCEED,
'found+"-"+g1', 'aa-a'),
('\\(a+\\)+\\1', 'aa', SUCCEED,
'found+"-"+g1', 'aa-a'),
('\\(a\\).+\\1', 'aba', SUCCEED,
'found+"-"+g1', 'aba-a'),
('\\(a\\)ba*\\1', 'aba', SUCCEED,
'found+"-"+g1', 'aba-a'),
('\\(aa\\|a\\)a\\1$', 'aaa', SUCCEED,
'found+"-"+g1', 'aaa-a'),
('\\(a\\|aa\\)a\\1$', 'aaa', SUCCEED,
'found+"-"+g1', 'aaa-a'),
('\\(a+\\)a\\1$', 'aaa', SUCCEED,
'found+"-"+g1', 'aaa-a'),
('\\([abc]*\\)\\1', 'abcabc', SUCCEED,
'found+"-"+g1', 'abcabc-abc'),
('\\(a\\)\\(b\\)c\\|ab', 'ab', SUCCEED,
'found+"-"+g1+"-"+g2', 'ab-None-None'),
('\\(a\\)+x', 'aaax', SUCCEED,
'found+"-"+g1', 'aaax-a'),
('\\([ac]\\)+x', 'aacx', SUCCEED,
'found+"-"+g1', 'aacx-c'),
('\\([^/]*/\\)*sub1/', 'd:msgs/tdir/sub1/trial/away.cpp', SUCCEED,
'found+"-"+g1', 'd:msgs/tdir/sub1/-tdir/'),
('\\([^.]*\\)\\.\\([^:]*\\):[T ]+\\(.*\\)', 'track1.title:TBlah blah blah', SUCCEED,
'found+"-"+g1+"-"+g2+"-"+g3', 'track1.title:TBlah blah blah-track1-title-Blah blah blah'),
('\\([^N]*N\\)+', 'abNNxyzN', SUCCEED,
'found+"-"+g1', 'abNNxyzN-xyzN'),
('\\([^N]*N\\)+', 'abNNxyz', SUCCEED,
'found+"-"+g1', 'abNN-N'),
('\\([abc]*\\)x', 'abcx', SUCCEED,
'found+"-"+g1', 'abcx-abc'),
('\\([abc]*\\)x', 'abc', FAIL),
('\\([xyz]*\\)x', 'abcx', SUCCEED,
'found+"-"+g1', 'x-'),
('\\(a\\)+b\\|aac', 'aac', SUCCEED,
'found+"-"+g1', 'aac-None'),
('\<a', 'a', SUCCEED, 'found', 'a'),
('\<a', '!', FAIL),
('a\<b', 'ab', FAIL),
('a\>', 'ab', FAIL),
('a\>', 'a!', SUCCEED, 'found', 'a'),
('a\>', 'a', SUCCEED, 'found', 'a'),
]
"""Simple HTTP Server.
This module builds on BaseHTTPServer by implementing the standard GET
and HEAD requests in a fairly straightforward manner.
"""
__version__ = "0.3"
import os
import sys
import time
import socket
import string
import posixpath
import SocketServer
import BaseHTTPServer
class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""Simple HTTP request handler with GET and HEAD commands.
This serves files from the current directory and any of its
subdirectories. It assumes that all files are plain text files
unless they have the extension ".html" in which case it assumes
they are HTML files.
The GET and HEAD requests are identical except that the HEAD
request omits the actual contents of the file.
"""
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()
def do_HEAD(self):
"""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
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
def copyfile(self, source, outputfile):
"""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 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)
def guess_type(self, path):
"""Guess the type of a file.
Argument is a PATH (a filename).
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.
"""
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',
}
def test(HandlerClass = SimpleHTTPRequestHandler,
ServerClass = SocketServer.TCPServer):
BaseHTTPServer.test(HandlerClass, ServerClass)
if __name__ == '__main__':
test()
This diff is collapsed.
# Module 'statcache'
#
# Maintain a cache of file stats.
# There are functions to reset the cache or to selectively remove items.
import os
from stat import *
# The cache.
# Keys are pathnames, values are `os.stat' outcomes.
#
cache = {}
# Stat a file, possibly out of the cache.
#
def stat(path):
if cache.has_key(path):
return cache[path]
cache[path] = ret = os.stat(path)
return ret
# Reset the cache completely.
#
def reset():
global cache
cache = {}
# Remove a given item from the cache, if it exists.
#
def forget(path):
if cache.has_key(path):
del cache[path]
# Remove all pathnames with a given prefix.
#
def forget_prefix(prefix):
n = len(prefix)
for path in cache.keys():
if path[:n] == prefix:
del cache[path]
# Forget about a directory and all entries in it, but not about
# entries in subdirectories.
#
def forget_dir(prefix):
if prefix[-1:] == '/' and prefix <> '/':
prefix = prefix[:-1]
forget(prefix)
if prefix[-1:] <> '/':
prefix = prefix + '/'
n = len(prefix)
for path in cache.keys():
if path[:n] == prefix:
rest = path[n:]
if rest[-1:] == '/': rest = rest[:-1]
if '/' not in rest:
del cache[path]
# Remove all pathnames except with a given prefix.
# Normally used with prefix = '/' after a chdir().
#
def forget_except_prefix(prefix):
n = len(prefix)
for path in cache.keys():
if path[:n] <> prefix:
del cache[path]
# Check for directory.
#
def isdir(path):
try:
st = stat(path)
except os.error:
return 0
return S_ISDIR(st[ST_MODE])
# class StringIO implements file-like objects that read/write a
# string buffer (a.k.a. "memory files").
#
# This implements (nearly) all stdio methods.
#
# f = StringIO() # ready for writing
# f = StringIO(buf) # ready for reading
# f.close() # explicitly release resources held
# flag = f.isatty() # always false
# pos = f.tell() # get current position
# f.seek(pos) # set current position
# f.seek(pos, mode) # mode 0: absolute; 1: relative; 2: relative to EOF
# buf = f.read() # read until EOF
# buf = f.read(n) # read up to n bytes
# buf = f.readline() # read until end of line ('\n') or EOF
# list = f.readlines()# list of f.readline() results until EOF
# f.write(buf) # write at current position
# f.writelines(list) # for line in list: f.write(line)
# f.getvalue() # return whole file's contents as a string
#
# Notes:
# - Using a real file is often faster (but less convenient).
# - fileno() is left unimplemented so that code which uses it triggers
# an exception early.
# - Seeking far beyond EOF and then writing will insert real null
# bytes that occupy space in the buffer.
# - There's a simple test set (see end of this file).
import string
class StringIO:
def __init__(self, buf = ''):
self.buf = buf
self.len = len(buf)
self.buflist = []
self.pos = 0
self.closed = 0
self.softspace = 0
def close(self):
if not self.closed:
self.closed = 1
del self.buf, self.pos
def isatty(self):
return 0
def seek(self, pos, mode = 0):
if self.buflist:
self.buf = self.buf + string.joinfields(self.buflist, '')
self.buflist = []
if mode == 1:
pos = pos + self.pos
elif mode == 2:
pos = pos + self.len
self.pos = max(0, pos)
def tell(self):
return self.pos
def read(self, n = -1):
if self.buflist:
self.buf = self.buf + string.joinfields(self.buflist, '')
self.buflist = []
if n < 0:
newpos = self.len
else:
newpos = min(self.pos+n, self.len)
r = self.buf[self.pos:newpos]
self.pos = newpos
return r
def readline(self, length=None):
if self.buflist:
self.buf = self.buf + string.joinfields(self.buflist, '')
self.buflist = []
i = string.find(self.buf, '\n', self.pos)
if i < 0:
newpos = self.len
else:
newpos = i+1
if length is not None:
if self.pos + length < newpos:
newpos = self.pos + length
r = self.buf[self.pos:newpos]
self.pos = newpos
return r
def readlines(self):
lines = []
line = self.readline()
while line:
lines.append(line)
line = self.readline()
return lines
def write(self, s):
if not s: return
if self.pos > self.len:
self.buflist.append('\0'*(self.pos - self.len))
self.len = self.pos
newpos = self.pos + len(s)
if self.pos < self.len:
if self.buflist:
self.buf = self.buf + string.joinfields(self.buflist, '')
self.buflist = []
self.buflist = [self.buf[:self.pos], s, self.buf[newpos:]]
self.buf = ''
else:
self.buflist.append(s)
self.len = newpos
self.pos = newpos
def writelines(self, list):
self.write(string.joinfields(list, ''))
def flush(self):
pass
def getvalue(self):
if self.buflist:
self.buf = self.buf + string.joinfields(self.buflist, '')
self.buflist = []
return self.buf
# A little test suite
def test():
import sys
if sys.argv[1:]:
file = sys.argv[1]
else:
file = '/etc/passwd'
lines = open(file, 'r').readlines()
text = open(file, 'r').read()
f = StringIO()
for line in lines[:-2]:
f.write(line)
f.writelines(lines[-2:])
if f.getvalue() != text:
raise RuntimeError, 'write failed'
length = f.tell()
print 'File length =', length
f.seek(len(lines[0]))
f.write(lines[1])
f.seek(0)
print 'First line =', `f.readline()`
here = f.tell()
line = f.readline()
print 'Second line =', `line`
f.seek(-len(line), 1)
line2 = f.read(len(line))
if line != line2:
raise RuntimeError, 'bad result after seek back'
f.seek(len(line2), 1)
list = f.readlines()
line = list[-1]
f.seek(f.tell() - len(line))
line2 = f.read()
if line != line2:
raise RuntimeError, 'bad result after seek back from EOF'
print 'Read', len(list), 'more lines'
print 'File length =', f.tell()
if f.tell() != length:
raise RuntimeError, 'bad length'
f.close()
if __name__ == '__main__':
test()
#! /usr/bin/env python
"""Test the arraymodule.
Roger E. Masse
"""
import array
from test_support import verbose, TESTFN, unlink
def main():
testtype('c', 'c')
for type in (['b', 'h', 'i', 'l', 'f', 'd']):
testtype(type, 1)
unlink(TESTFN)
def testtype(type, example):
a = array.array(type)
a.append(example)
if verbose:
print 40*'*'
print 'array after append: ', a
a.typecode
a.itemsize
if a.typecode in ('i', 'b', 'h', 'l'):
a.byteswap()
if a.typecode == 'c':
f = open(TESTFN, "w")
f.write("The quick brown fox jumps over the lazy dog.\n")
f.close()
f = open(TESTFN, 'r')
a.fromfile(f, 10)
f.close()
if verbose:
print 'char array with 10 bytes of TESTFN appended: ', a
a.fromlist(['a', 'b', 'c'])
if verbose:
print 'char array with list appended: ', a
a.insert(0, example)
if verbose:
print 'array of %s after inserting another:' % a.typecode, a
f = open(TESTFN, 'w')
a.tofile(f)
f.close()
a.tolist()
a.tostring()
if verbose:
print 'array of %s converted to a list: ' % a.typecode, a.tolist()
if verbose:
print 'array of %s converted to a string: ' \
% a.typecode, a.tostring()
main()
This diff is collapsed.
#! /usr/bin/env python
"""Test script for the binascii C module
Uses the mechanism of the python binhex module
Roger E. Masse
"""
import binhex
import tempfile
from test_support import verbose
def test():
try:
fname1 = tempfile.mktemp()
fname2 = tempfile.mktemp()
f = open(fname1, 'w')
except:
raise ImportError, "Cannot test binascii without a temp file"
start = 'Jack is my hero'
f.write(start)
f.close()
binhex.binhex(fname1, fname2)
if verbose:
print 'binhex'
binhex.hexbin(fname2, fname1)
if verbose:
print 'hexbin'
f = open(fname1, 'r')
finish = f.readline()
if start <> finish:
print 'Error: binhex <> hexbin'
elif verbose:
print 'binhex == hexbin'
try:
import os
os.unlink(fname1)
os.unlink(fname2)
except:
pass
test()
This diff is collapsed.
# Python test set -- part 4, built-in functions
from test_support import *
print '4. Built-in functions'
print 'test_b1'
unload('test_b1')
import test_b1
print 'test_b2'
unload('test_b2')
import test_b2
This diff is collapsed.
#! /usr/bin/env python
"""Simple test script for cryptmodule.c
Roger E. Masse
"""
from test_support import verbose
import crypt
c = crypt.crypt('mypassword', 'ab')
if verbose:
print 'Test encryption: ', c
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# Python test set -- part 3, built-in operations.
print '3. Operations'
print 'XXX Not yet implemented'
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment