From 9a22de101fd66c6e0d1a6dda515a7b31d8c9c9aa Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 12 Jan 1995 12:29:47 +0000 Subject: new files --- Lib/Complex.py | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Lib/cgi.py | 278 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Lib/popen2.py | 35 ++++++++ Lib/rexec.py | 184 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 772 insertions(+) create mode 100644 Lib/Complex.py create mode 100755 Lib/cgi.py create mode 100644 Lib/popen2.py create mode 100644 Lib/rexec.py diff --git a/Lib/Complex.py b/Lib/Complex.py new file mode 100644 index 0000000..f4892f3 --- /dev/null +++ b/Lib/Complex.py @@ -0,0 +1,275 @@ +# 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() diff --git a/Lib/cgi.py b/Lib/cgi.py new file mode 100755 index 0000000..d412109 --- /dev/null +++ b/Lib/cgi.py @@ -0,0 +1,278 @@ +#!/usr/local/bin/python +# +# A class for wrapping the WWW Forms Common Gateway Interface (CGI) +# Michael McLay, NIST mclay@eeel.nist.gov 6/14/94 +# +# modified by Steve Majewski 12/5/94 +# + +# Several classes to parse the name/value pairs that are passed to +# a server's CGI by GET, POST or PUT methods by a WWW FORM. This +# module is based on Mike McLay's original cgi.py after discussing +# changes with him and others on the comp.lang.python newsgroup, and +# at the NIST Python workshop. +# +# The rationale for changes was: +# The original FormContent class was almost, but not quite like +# a dictionary object. Besides adding some extra access methods, +# it had a values() method with different arguments and semantics +# from the standard values() method of a mapping object. Also, +# it provided several different access methods that may be necessary +# or useful, but made it a little more confusing to figure out how +# to use. Also, we wanted to make the most typical cases the simplest +# and most convenient access methods. ( Most form fields just return +# a single value, and in practice, a lot of code was just assuming +# a single value and ignoring all others. On the other hand, the +# protocol allows multiple values to be returned. +# +# The new base class (FormContentDict) is just like a dictionary. +# In fact, if you just want a dictionary, all of the stuff that was +# in __init__ has been extracted into a cgi.parse() function that will +# return the "raw" dictionary, but having a class allows you to customize +# it further. +# Mike McLay's original FormContent class is reimplemented as a +# subclass of FormContentDict. +# There are two additional sub-classes, but I'm not yet too sure +# whether they are what I want. +# + +import string,regsub,sys,os,urllib +# since os.environ may often be used in cgi code, we name it in this module. +from os import environ + + +def parse(): + if environ['REQUEST_METHOD'] == 'POST': + qs = sys.stdin.read(string.atoi(environ['CONTENT_LENGTH'])) + environ['QUERY_STRING'] = qs + else: + qs = environ['QUERY_STRING'] + name_value_pairs = string.splitfields(qs, '&') + dict = {} + for name_value in name_value_pairs: + nv = string.splitfields(name_value, '=') + if len(nv) != 2: + continue + name = nv[0] + value = urllib.unquote(regsub.gsub('+',' ',nv[1])) + if len(value): + if dict.has_key (name): + dict[name].append(value) + else: + dict[name] = [value] + return dict + + + +# The FormContent constructor creates a dictionary from the name/value pairs +# passed through the CGI interface. + + +# +# form['key'] +# form.__getitem__('key') +# form.has_key('key') +# form.keys() +# form.values() +# form.items() +# form.dict + +class FormContentDict: + def __init__( self ): + self.dict = parse() + self.query_string = environ['QUERY_STRING'] + def __getitem__(self,key): + return self.dict[key] + def keys(self): + return self.dict.keys() + def has_key(self, key): + return self.dict.has_key(key) + def values(self): + return self.dict.values() + def items(self): + return self.dict.items() + def __len__( self ): + return len(self.dict) + + +# This is the "strict" single-value expecting version. +# IF you only expect a single value for each field, then form[key] +# will return that single value ( the [0]-th ), and raise an +# IndexError if that expectation is not true. +# IF you expect a field to have possible multiple values, than you +# can use form.getlist( key ) to get all of the values. +# values() and items() are a compromise: they return single strings +# where there is a single value, and lists of strings otherwise. + +class SvFormContentDict(FormContentDict): + def __getitem__( self, key ): + if len( self.dict[key] ) > 1 : + raise IndexError, 'expecting a single value' + return self.dict[key][0] + def getlist( self, key ): + return self.dict[key] + def values( self ): + lis = [] + for each in self.dict.values() : + if len( each ) == 1 : + lis.append( each[0] ) + else: lis.append( each ) + return lis + def items( self ): + lis = [] + for key,value in self.dict.items(): + if len(value) == 1 : + lis.append( (key,value[0]) ) + else: lis.append( (key,value) ) + return lis + + +# And this sub-class is similar to the above, but it will attempt to +# interpret numerical values. This is here as mostly as an example, +# but I think the real way to handle typed-data from a form may be +# to make an additional table driver parsing stage that has a table +# of allowed input patterns and the output conversion types - it +# would signal type-errors on parse, not on access. +class InterpFormContentDict(SvFormContentDict): + def __getitem__( self, key ): + v = SvFormContentDict.__getitem__( self, key ) + if v[0] in string.digits+'+-.' : + try: return string.atoi( v ) + except ValueError: + try: return string.atof( v ) + except ValueError: pass + return string.strip(v) + def values( self ): + lis = [] + for key in self.keys(): + try: + lis.append( self[key] ) + except IndexError: + lis.append( self.dict[key] ) + return lis + def items( self ): + lis = [] + for key in self.keys(): + try: + lis.append( (key, self[key]) ) + except IndexError: + lis.append( (key, self.dict[key]) ) + return lis + + +# class FormContent parses the name/value pairs that are passed to a +# server's CGI by GET, POST, or PUT methods by a WWW FORM. several +# specialized FormContent dictionary access methods have been added +# for convenience. + +# function return value +# +# form.keys() all keys in dictionary +# form.has_key('key') test keys existance +# form[key] returns list associated with key +# form.values('key') key's list (same as form.[key]) +# form.indexed_value('key' index) nth element in key's value list +# form.value(key) key's unstripped value +# form.length(key) number of elements in key's list +# form.stripped(key) key's value with whitespace stripped +# form.pars() full dictionary + + + +class FormContent(FormContentDict): +# This is the original FormContent semantics of values, +# not the dictionary like semantics. + def values(self,key): + if self.dict.has_key(key):return self.dict[key] + else: return None + def indexed_value(self,key, location): + if self.dict.has_key(key): + if len (self.dict[key]) > location: + return self.dict[key][location] + else: return None + else: return None + def value(self,key): + if self.dict.has_key(key):return self.dict[key][0] + else: return None + def length(self,key): + return len (self.dict[key]) + def stripped(self,key): + if self.dict.has_key(key):return string.strip(self.dict[key][0]) + else: return None + def pars(self): + return self.dict + + + + + + +def print_environ_usage(): + print """ +

These operating system environment variables could have been +set:

+""" + +def print_environ(): + skeys = environ.keys() + skeys.sort() + print '

The following environment variables were set by the CGI script:

' + print '
' + for key in skeys: + print '
',key, '
', environ[key] + print '
' + +def print_form( form ): + print '

The following name/value pairs were entered in the form:

' + print '
' + skeys = form.keys() + skeys.sort() + for key in skeys: + print '
',key, ' : ',escape(`type(form[key])`),' ','
', form[key] + print '
' + +def escape( s ): + return regsub.gsub( '<', '<', regsub.gsub( '>' , '>', s )) + +def test( what ): + label = escape(str(what)) + print 'Content-type: text/html\n\n' + print '
\n' + label + '\n
\n' + print '\n' + print "

" + label +"

\n" + form = what() + print_form( form ) + print_environ() + print_environ_usage() + print '' + +if __name__ == '__main__' : + test_classes = ( FormContent, FormContentDict, SvFormContentDict, InterpFormContentDict ) + test( test_classes[0] ) # by default, test compatibility with + # old version, change index to test others. diff --git a/Lib/popen2.py b/Lib/popen2.py new file mode 100644 index 0000000..d195fef --- /dev/null +++ b/Lib/popen2.py @@ -0,0 +1,35 @@ +import os +import sys +import string + +MAXFD = 100 # Max number of file descriptors (os.getdtablesize()???) + +def popen2(cmd): + cmd = string.split(cmd) + p2cread, p2cwrite = os.pipe() + c2pread, c2pwrite = os.pipe() + pid = os.fork() + if pid == 0: + # Child + os.close(0) + os.close(1) + if os.dup(p2cread) <> 0: + sys.stderr.write('popen2: bad read dup\n') + if os.dup(c2pwrite) <> 1: + sys.stderr.write('popen2: bad write dup\n') + for i in range(3, MAXFD): + try: + os.close(i) + except: + pass + try: + os.execv(cmd[0], cmd) + finally: + os._exit(1) + # Shouldn't come here, I guess + os._exit(1) + os.close(p2cread) + tochild = os.fdopen(p2cwrite, 'w') + os.close(c2pwrite) + fromchild = os.fdopen(c2pread, 'r') + return fromchild, tochild diff --git a/Lib/rexec.py b/Lib/rexec.py new file mode 100644 index 0000000..0e6ba20 --- /dev/null +++ b/Lib/rexec.py @@ -0,0 +1,184 @@ +# Implement restricted execution of Python code + +import __builtin__ +import new +import os +import sys +import types + +def trace(fmt, *args): + if 0: + sys.stderr.write(fmt % args + '\n') + +def copydict(src, dst, exceptions = [], only = None): + if only is None: + for key in src.keys(): + if key not in exceptions: + dst[key] = src[key] + else: + for key in only: + dst[key] = src[key] + +def copymodule(src, dst, exceptions = [], only = None): + copydict(src.__dict__, dst.__dict__, exceptions, only) + +safe_path = ['/ufs/guido/lib/python'] +safe_modules = ['array', 'math', 'regex', 'strop', 'time'] +unsafe_builtin_names = ['open', 'reload', '__import__', + 'eval', 'execfile', 'dir', 'vars', + 'raw_input', 'input'] +safe_posix_names = ['error', 'fstat', 'listdir', 'lstat', 'readlink', 'stat', + 'times', 'uname', 'getpid', 'getppid', 'getcwd', + 'getuid', 'getgid', 'geteuid', 'getegid'] + +safe_sys = new.module('sys') +safe_sys.modules = {} +safe_sys.modules['sys'] = safe_sys +safe_sys.path = safe_path[:] +safe_sys.argv = ['-'] +safe_sys.builtin_module_names = safe_modules[:] + ['posix'] +safe_sys.builtin_module_names.sort() +safe_sys.copyright = sys.copyright +safe_sys.version = sys.version + ' [restricted mode]' +safe_sys.exit = sys.exit + +def new_module(name): + safe_sys.modules[name] = m = new.module(name) + return m + +safe_builtin = new_module('__builtin__') +copymodule(__builtin__, safe_builtin, unsafe_builtin_names) + +safe_main = new_module('__main__') + +safe_posix = new_module('posix') +import posix +copymodule(posix, safe_posix, None, safe_posix_names) +safe_posix.environ = {} +copydict(posix.environ, safe_posix.environ) + +safe_types = new_module('types') +copymodule(types, safe_types) + +def safe_import(name): + if safe_sys.modules.has_key(name): + return safe_sys.modules[name] + if name in safe_modules: + temp = {} + exec "import "+name in temp + m = new_module(name) + copymodule(temp[name], m) + return m + for dirname in safe_path: + filename = os.path.join(dirname, name + '.py') + try: + f = open(filename, 'r') + f.close() + except IOError: + continue + m = new_module(name) + rexecfile(filename, m.__dict__) + return m + raise ImportError, name +safe_builtin.__import__ = safe_import + +def safe_open(file, mode = 'r'): + if type(file) != types.StringType or type(mode) != types.StringType: + raise TypeError, 'open argument(s) must be string(s)' + if mode not in ('r', 'rb'): + raise IOError, 'open for writing not allowed' + if '/' in file: + raise IOError, 'open pathname not allowed' + return open(file, mode) +safe_builtin.open = safe_open + +def safe_dir(object = safe_main): + keys = object.__dict__.keys() + keys.sort() + return keys +safe_builtin.dir = safe_dir + +def safe_vars(object = safe_main): + keys = safe_dir(object) + dict = {} + copydict(object.__dict__, dict, None, keys) + return dict +safe_builtin.vars = safe_vars + + +def exterior(): + """Return env of caller's caller, as triple: (name, locals, globals). + + Name will be None if env is __main__, and locals will be None if same + as globals, ie local env is global env.""" + + import sys, __main__ + + bogus = 'bogus' # A locally usable exception + try: raise bogus # Force an exception + except bogus: + at = sys.exc_traceback.tb_frame.f_back # The external frame. + if at.f_back: at = at.f_back # And further, if any. + where, globals, locals = at.f_code, at.f_globals, at.f_locals + if locals == globals: # Exterior is global? + locals = None + if where: + where = where.co_name + return (where, locals, globals) + + +def rexec(str, globals = None, locals = None): + trace('rexec(%s, ...)', `str`) + if globals is None: + globals = locals = exterior()[2] + elif locals is None: + locals = globals + globals['__builtins__'] = safe_builtin.__dict__ + safe_sys.stdout = sys.stdout + safe_sys.stderr = sys.stderr + exec str in globals, locals + +def rexecfile(file, globals = None, locals = None): + trace('rexecfile(%s, ...)', `file`) + if globals is None: + globals = locals = exterior()[2] + elif locals is None: + locals = globals + globals['__builtins__'] = safe_builtin.__dict__ + safe_sys.stdout = sys.stdout + safe_sys.stderr = sys.stderr + return execfile(file, globals, locals) + +def reval(str, globals = None, locals = None): + trace('reval(%s, ...)', `str`) + if globals is None: + globals = locals = exterior()[2] + elif locals is None: + locals = globals + globals['__builtins__'] = safe_builtin.__dict__ + safe_sys.stdout = sys.stdout + safe_sys.stderr = sys.stderr + return eval(str, globals, locals) +safe_builtin.eval = reval + + +def test(): + import traceback + g = {} + while 1: + try: + s = raw_input('--> ') + except EOFError: + break + try: + try: + c = compile(s, '', 'eval') + except: + rexec(s, g) + else: + print reval(c, g) + except: + traceback.print_exc() + +if __name__ == '__main__': + test() -- cgit v0.12