[Zope-Checkins] CVS: Zope3/lib/python/Zope/RestrictedPython - Eval.py:1.1.2.1 Guards.py:1.1.2.1 MutatingWalker.py:1.1.2.1 PrintCollector.py:1.1.2.1 RCompile.py:1.1.2.1 RestrictionMutator.py:1.1.2.1 Utilities.py:1.1.2.1 ZopeGuards.py:1.1.2.1 __init__.py:1.1.2.1
Fred L. Drake, Jr.
fdrake@acm.org
Wed, 27 Feb 2002 17:29:57 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/RestrictedPython
In directory cvs.zope.org:/tmp/cvs-serv17295
Added Files:
Tag: Zope-3x-branch
Eval.py Guards.py MutatingWalker.py PrintCollector.py
RCompile.py RestrictionMutator.py Utilities.py ZopeGuards.py
__init__.py
Log Message:
Python 2.2 version of RestrictedPython (mostly cleanup).
=== Added File Zope3/lib/python/Zope/RestrictedPython/Eval.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Restricted Python Expressions
"""
__rcs_id__='$Id: Eval.py,v 1.1.2.1 2002/02/27 22:29:56 fdrake Exp $'
__version__='$Revision: 1.1.2.1 $'[11:-2]
import string
compile_restricted_eval = None
nltosp = string.maketrans('\r\n',' ')
default_guarded_getattr = getattr # No restrictions.
def default_guarded_getitem(ob, index):
# No restrictions.
return ob[index]
PROFILE = 0
class RestrictionCapableEval:
"""A base class for restricted code.
"""
globals = {'__builtins__': None}
rcode = None # restricted
ucode = None # unrestricted
used = None
def __init__(self, expr):
"""Create a restricted expression
where:
expr -- a string containing the expression to be evaluated.
"""
expr = expr.strip()
self.__name__ = expr
expr = string.translate(expr, nltosp)
self.expr = expr
self.prepUnrestrictedCode() # Catch syntax errors.
def prepRestrictedCode(self):
if self.rcode is None:
global compile_restricted_eval
if compile_restricted_eval is None:
# Late binding because this will import the whole
# compiler suite.
from Zope.RestrictedPython import compile_restricted_eval
if PROFILE:
from time import clock
start = clock()
co, err, warn, used = compile_restricted_eval(
self.expr, '<string>')
if PROFILE:
end = clock()
print 'prepRestrictedCode: %d ms for %s' % (
(end - start) * 1000, `self.expr`)
if err:
raise SyntaxError, err[0]
self.used = tuple(used.keys())
self.rcode = co
def prepUnrestrictedCode(self):
if self.ucode is None:
# Use the standard compiler.
co = compile(self.expr, '<string>', 'eval')
if self.used is None:
# Examine the code object, discovering which names
# the expression needs.
names=list(co.co_names)
used={}
i=0
code=co.co_code
l=len(code)
LOAD_NAME=101
HAVE_ARGUMENT=90
while(i < l):
c=ord(code[i])
if c==LOAD_NAME:
name=names[ord(code[i+1])+256*ord(code[i+2])]
used[name]=1
i=i+3
elif c >= HAVE_ARGUMENT: i=i+3
else: i=i+1
self.used=tuple(used.keys())
self.ucode=co
def eval(self, mapping):
# This default implementation is probably not very useful. :-(
# This is meant to be overridden.
self.prepRestrictedCode()
code = self.rcode
d = {'_getattr_': default_guarded_getattr,
'_getitem_': default_guarded_getitem}
d.update(self.globals)
has_key = d.has_key
for name in self.used:
try:
if not has_key(name):
d[name] = mapping[name]
except KeyError:
# Swallow KeyErrors since the expression
# might not actually need the name. If it
# does need the name, a NameError will occur.
pass
return eval(code, d)
def __call__(self, **kw):
return self.eval(kw)
=== Added File Zope3/lib/python/Zope/RestrictedPython/Guards.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
from __future__ import nested_scopes
__version__='$Revision: 1.1.2.1 $'[11:-2]
safe_builtins = {}
for name in ('None', 'abs', 'chr', 'divmod', 'float', 'hash', 'hex', 'int',
'len', 'max', 'min', 'oct', 'ord', 'round', 'str', 'pow',
'apply', 'callable', 'cmp', 'complex', 'isinstance',
'issubclass', 'long', 'repr', 'range', 'list', 'tuple',
'unichr', 'unicode', 'zip', 'map', 'reduce',
'Exception',
'ArithmeticError', 'AssertionError', 'AttributeError',
'EOFError', 'EnvironmentError', 'FloatingPointError',
'IOError', 'ImportError', 'IndexError', 'KeyError',
'LookupError', 'NameError', 'OSError', 'OverflowError',
'RuntimeError', 'StandardError', 'SyntaxError',
'TypeError', 'ValueError', 'ZeroDivisionError',):
safe_builtins[name] = __builtins__[name]
def _write_wrapper():
# Construct the write wrapper class
def _handler(secattr, error_msg):
# Make a class method.
def handler(self, *args):
try:
f = getattr(self.ob, secattr)
except AttributeError:
raise TypeError, error_msg
f(*args)
return handler
class Wrapper:
def __len__(self):
# Required for slices with negative bounds.
return len(self.ob)
def __init__(self, ob):
self.__dict__['ob'] = ob
__setitem__ = _handler('__guarded_setitem__',
'object does not support item or slice assignment')
__delitem__ = _handler('__guarded_delitem__',
'object does not support item or slice assignment')
__setattr__ = _handler('__guarded_setattr__',
'attribute-less object (assign or del)')
__delattr__ = _handler('__guarded_delattr__',
'attribute-less object (assign or del)')
return Wrapper
def _full_write_guard():
# Nested scope abuse!
# safetype and Wrapper variables are used by guard()
safetype = {type([]): 1, type({}): 1}.has_key
Wrapper = _write_wrapper()
def guard(ob, safetype=safetype, Wrapper=Wrapper):
# Don't bother wrapping simple types, or objects that claim to
# handle their own write security.
if safetype(type(ob)) or hasattr(ob, '_guarded_writes'):
return ob
# Hand the object to the Wrapper instance, then return the instance.
return Wrapper(ob)
return guard
full_write_guard = _full_write_guard()
def guarded_setattr(object, name, value):
setattr(full_write_guard(object), name, value)
safe_builtins['setattr'] = guarded_setattr
def guarded_delattr(object, name):
delattr(full_write_guard(object), name)
safe_builtins['delattr'] = guarded_delattr
=== Added File Zope3/lib/python/Zope/RestrictedPython/MutatingWalker.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
__version__='$Revision: 1.1.2.1 $'[11:-2]
from compiler import ast
ListType = type([])
TupleType = type(())
SequenceTypes = (ListType, TupleType)
class MutatingWalker:
def __init__(self, visitor):
self.visitor = visitor
self._cache = {}
def defaultVisitNode(self, node, walker=None, exclude=None):
for name, child in node.__dict__.items():
if exclude is not None and name in exclude:
continue
v = self.dispatchObject(child)
if v is not child:
# Replace the node.
node.__dict__[name] = v
return node
def visitSequence(self, seq):
res = seq
for idx in range(len(seq)):
child = seq[idx]
v = self.dispatchObject(child)
if v is not child:
# Change the sequence.
if type(res) is ListType:
res[idx : idx + 1] = [v]
else:
res = res[:idx] + (v,) + res[idx + 1:]
return res
def dispatchObject(self, ob):
'''
Expected to return either ob or something that will take
its place.
'''
if isinstance(ob, ast.Node):
return self.dispatchNode(ob)
elif type(ob) in SequenceTypes:
return self.visitSequence(ob)
else:
return ob
def dispatchNode(self, node):
klass = node.__class__
meth = self._cache.get(klass, None)
if meth is None:
className = klass.__name__
meth = getattr(self.visitor, 'visit' + className,
self.defaultVisitNode)
self._cache[klass] = meth
return meth(node, self)
def walk(tree, visitor):
return MutatingWalker(visitor).dispatchNode(tree)
=== Added File Zope3/lib/python/Zope/RestrictedPython/PrintCollector.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
__version__='$Revision: 1.1.2.1 $'[11:-2]
class PrintCollector:
'''Collect written text, and return it when called.'''
def __init__(self):
self.txt = []
def write(self, text):
self.txt.append(text)
def __call__(self):
return ''.join(self.txt)
=== Added File Zope3/lib/python/Zope/RestrictedPython/RCompile.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Compiles restricted code using the compiler module from the
Python standard library.
"""
__version__='$Revision: 1.1.2.1 $'[11:-2]
from compiler import ast, parse, misc, syntax
from compiler.pycodegen import AbstractCompileMode, Expression, \
Interactive, Module
from traceback import format_exception_only
import MutatingWalker
from RestrictionMutator import RestrictionMutator
def niceParse(source, filename, mode):
try:
return parse(source, mode)
except:
# Try to make a clean error message using
# the builtin Python compiler.
try:
compile(source, filename, mode)
except SyntaxError:
raise
# Some other error occurred.
raise
class RestrictedCompileMode (AbstractCompileMode):
def __init__(self, source, filename):
self.rm = RestrictionMutator()
AbstractCompileMode.__init__(self, source, filename)
def parse(self):
return niceParse(self.source, self.filename, self.mode)
def _get_tree(self):
tree = self.parse()
rm = self.rm
MutatingWalker.walk(tree, rm)
if rm.errors:
raise SyntaxError, rm.errors[0]
misc.set_filename(self.filename, tree)
syntax.check(tree)
return tree
class RExpression(RestrictedCompileMode, Expression):
mode = "eval"
compile = Expression.compile
class RInteractive(RestrictedCompileMode, Interactive):
mode = "single"
compile = Interactive.compile
class RModule(RestrictedCompileMode, Module):
mode = "exec"
compile = Module.compile
class RFunction(RModule):
"""A restricted Python function built from parts.
"""
def __init__(self, p, body, name, filename):
self.params = p
self.body = body
self.name = name
RModule.__init__(self, None, filename)
def parse(self):
# Parse the parameters and body, then combine them.
firstline = 'def f(%s): pass' % self.params
tree = niceParse(firstline, '<function parameters>', 'exec')
f = tree.node.nodes[0]
body_code = niceParse(self.body, self.filename, 'exec')
# Stitch the body code into the function.
f.code.nodes = body_code.node.nodes
f.name = self.name
# Look for a docstring.
stmt1 = f.code.nodes[0]
if (isinstance(stmt1, ast.Discard) and
isinstance(stmt1.expr, ast.Const) and
type(stmt1.expr.value) is type('')):
f.doc = stmt1.expr.value
return tree
def compileAndTuplize(gen):
try:
gen.compile()
except SyntaxError, v:
return None, (str(v),), gen.rm.warnings, gen.rm.used_names
return gen.getCode(), (), gen.rm.warnings, gen.rm.used_names
def compile_restricted_function(p, body, name, filename):
"""Compiles a restricted code object for a function.
The function can be reconstituted using the 'new' module:
new.function(<code>, <globals>)
"""
gen = RFunction(p, body, name, filename)
return compileAndTuplize(gen)
def compile_restricted_exec(s, filename='<string>'):
"""Compiles a restricted code suite.
"""
gen = RModule(s, filename)
return compileAndTuplize(gen)
def compile_restricted_eval(s, filename='<string>'):
"""Compiles a restricted expression.
"""
gen = RExpression(s, filename)
return compileAndTuplize(gen)
def compile_restricted(source, filename, mode):
"""Replacement for the builtin compile() function.
"""
if mode == "single":
gen = RInteractive(source, filename)
elif mode == "exec":
gen = RModule(source, filename)
elif mode == "eval":
gen = RExpression(source, filename)
else:
raise ValueError("compile_restricted() 3rd arg must be 'exec' or "
"'eval' or 'single'")
gen.compile()
return gen.getCode()
=== Added File Zope3/lib/python/Zope/RestrictedPython/RestrictionMutator.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
'''
RestrictionMutator modifies a tree produced by
compiler.transformer.Transformer, restricting and enhancing the
code in various ways before sending it to pycodegen.
'''
__version__='$Revision: 1.1.2.1 $'[11:-2]
from compiler import ast, parse
from compiler.consts import OP_ASSIGN, OP_DELETE, OP_APPLY
# These utility functions allow us to generate AST subtrees without
# line number attributes. These trees can then be inserted into other
# trees without affecting line numbers shown in tracebacks, etc.
def rmLineno(node):
'''Strip lineno attributes from a code tree'''
if node.__dict__.has_key('lineno'):
del node.lineno
for child in node.getChildren():
if isinstance(child, ast.Node):
rmLineno(child)
def stmtNode(txt):
'''Make a "clean" statement node'''
node = parse(txt).node.nodes[0]
rmLineno(node)
return node
def exprNode(txt):
'''Make a "clean" expression node'''
return stmtNode(txt).expr
# There should be up to four objects in the global namespace.
# If a wrapper function or print target is needed in a particular
# module or function, it is obtained from one of these objects.
# It is stored in a variable with the same name as the global
# object, but without a single trailing underscore. This variable is
# local, and therefore efficient to access, in function scopes.
_print_target_name = ast.Name('_print')
_getattr_name = ast.Name('_getattr')
_getattr_name_expr = ast.Name('_getattr_')
_getitem_name = ast.Name('_getitem')
_getitem_name_expr = ast.Name('_getitem_')
_write_guard_name = ast.Name('_write')
# Constants.
_None_const = ast.Const(None)
_write_const = ast.Const('write')
# Example prep code:
#
# global _getattr_
# _getattr = _getattr_
_prep_code = {}
for _n in ('getattr', 'getitem', 'write', 'print'):
_prep_code[_n] = [ast.Global(['_%s_' % _n]),
stmtNode('_%s = _%s_' % (_n, _n))]
# Call the global _print instead of copying it.
_prep_code['print'][1] = stmtNode('_print = _print_()')
_printed_expr = exprNode('_print()')
# Keep track of which restrictions have been applied in a given scope.
class FuncInfo:
_print_used = 0
_printed_used = 0
_getattr_used = 0
_getitem_used = 0
_write_used = 0
_is_suite = 0 # True for modules and functions, false for expressions
class RestrictionMutator:
def __init__(self):
self.funcinfo = FuncInfo()
self.warnings = []
self.errors = []
self.used_names = {}
def error(self, node, info):
lineno = getattr(node, 'lineno', None)
if lineno is not None and lineno > 0:
self.errors.append('Line %d: %s' % (lineno, info))
else:
self.errors.append(info)
def checkName(self, node, name):
if len(name) > 1 and name[0] == '_':
# Note: "_" *is* allowed.
self.error(node, '"%s" is an invalid variable name because'
' it starts with "_"' % name)
if name == 'printed':
self.error(node, '"printed" is a reserved name.')
def checkAttrName(self, node):
# This prevents access to protected attributes of guards
# and is thus essential regardless of the security policy,
# unless some other solution is devised.
name = node.attrname
if len(name) > 1 and name[0] == '_':
# Note: "_" *is* allowed.
self.error(node, '"%s" is an invalid attribute name '
'because it starts with "_".' % name)
def prepBody(self, body):
"""Appends prep code to the beginning of a code suite.
"""
info = self.funcinfo
if info._print_used or info._printed_used:
# Add code at top for creating _print_target
body[0:0] = _prep_code['print']
if not info._printed_used:
self.warnings.append(
"Prints, but never reads 'printed' variable.")
elif not info._print_used:
self.warnings.append(
"Doesn't print, but reads 'printed' variable.")
if info._getattr_used:
body[0:0] = _prep_code['getattr']
if info._getitem_used:
body[0:0] = _prep_code['getitem']
if info._write_used:
body[0:0] = _prep_code['write']
def visitFunction(self, node, walker):
self.checkName(node, node.name)
for argname in node.argnames:
self.checkName(node, argname)
walker.visitSequence(node.defaults)
former_funcinfo = self.funcinfo
self.funcinfo = FuncInfo()
self.funcinfo._is_suite = 1
node = walker.defaultVisitNode(node, exclude=('defaults',))
self.prepBody(node.code.nodes)
self.funcinfo = former_funcinfo
return node
def visitLambda(self, node, walker):
for argname in node.argnames:
self.checkName(node, argname)
return walker.defaultVisitNode(node)
def visitPrint(self, node, walker):
node = walker.defaultVisitNode(node)
self.funcinfo._print_used = 1
if node.dest is None:
node.dest = _print_target_name
else:
self.funcinfo._getattr_used = 1
# Pre-validate access to the "write" attribute.
# "print >> ob, x" becomes
# "print >> (_getattr(ob, 'write') and ob), x"
node.dest = ast.And([
ast.CallFunc(_getattr_name, [node.dest, _write_const]),
node.dest])
return node
visitPrintnl = visitPrint
def visitName(self, node, walker):
if node.name == 'printed':
# Replace name lookup with an expression.
self.funcinfo._printed_used = 1
return _printed_expr
self.checkName(node, node.name)
self.used_names[node.name] = 1
return node
def visitAssName(self, node, walker):
self.checkName(node, node.name)
return node
def visitGetattr(self, node, walker):
self.checkAttrName(node)
node = walker.defaultVisitNode(node)
if getattr(node, 'in_aug_assign', 0):
# We're in an augmented assignment
# We might support this later...
self.error(node, 'Augmented assignment of '
'attributes is not allowed.')
#expr.append(_write_guard_name)
#self.funcinfo._write_used = 1
self.funcinfo._getattr_used = 1
if self.funcinfo._is_suite:
ga = _getattr_name
else:
ga = _getattr_name_expr
return ast.CallFunc(ga, [node.expr, ast.Const(node.attrname)])
def visitSubscript(self, node, walker):
node = walker.defaultVisitNode(node)
if node.flags == OP_APPLY:
# get subscript or slice
if getattr(node, 'in_aug_assign', 0):
# We're in an augmented assignment
# We might support this later...
self.error(node, 'Augmented assignment of '
'object items and slices is not allowed.')
#expr.append(_write_guard_name)
#self.funcinfo._write_used = 1
self.funcinfo._getitem_used = 1
if hasattr(node, 'subs'):
# Subscript.
subs = node.subs
if len(subs) > 1:
# example: ob[1,2]
subs = ast.Tuple(subs)
else:
# example: ob[1]
subs = subs[0]
else:
# Slice.
# example: obj[0:2]
lower = node.lower
if lower is None:
lower = _None_const
upper = node.upper
if upper is None:
upper = _None_const
subs = ast.Sliceobj([lower, upper])
if self.funcinfo._is_suite:
gi = _getitem_name
else:
gi = _getitem_name_expr
return ast.CallFunc(gi, [node.expr, subs])
elif node.flags in (OP_DELETE, OP_ASSIGN):
# set or remove subscript or slice
node.expr = ast.CallFunc(_write_guard_name, [node.expr])
self.funcinfo._write_used = 1
return node
visitSlice = visitSubscript
def visitAssAttr(self, node, walker):
self.checkAttrName(node)
node = walker.defaultVisitNode(node)
node.expr = ast.CallFunc(_write_guard_name, [node.expr])
self.funcinfo._write_used = 1
return node
def visitExec(self, node, walker):
self.error(node, 'Exec statements are not allowed.')
def visitYield(self, node, walker):
self.error(node, 'Yield statements are not allowed.')
def visitClass(self, node, walker):
# Should classes be allowed at all??
self.checkName(node, node.name)
return walker.defaultVisitNode(node)
def visitModule(self, node, walker):
self.funcinfo._is_suite = 1
node = walker.defaultVisitNode(node)
self.prepBody(node.node.nodes)
return node
def visitAugAssign(self, node, walker):
node.node.in_aug_assign = 1
return walker.defaultVisitNode(node)
=== Added File Zope3/lib/python/Zope/RestrictedPython/Utilities.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
__version__='$Revision: 1.1.2.1 $'[11:-2]
import string, math, random, whrandom
utility_builtins = {}
utility_builtins['string'] = string
utility_builtins['math'] = math
utility_builtins['random'] = random
utility_builtins['whrandom'] = whrandom
try:
import DateTime
utility_builtins['DateTime']= DateTime.DateTime
except: pass
def same_type(arg1, *args):
'''Compares the class or type of two or more objects.'''
t = getattr(arg1, '__class__', type(arg1))
for arg in args:
if getattr(arg, '__class__', type(arg)) is not t:
return 0
return 1
utility_builtins['same_type'] = same_type
def test(*args):
l=len(args)
for i in range(1, l, 2):
if args[i-1]: return args[i]
if l%2: return args[-1]
utility_builtins['test'] = test
def reorder(s, with=None, without=()):
# s, with, and without are sequences treated as sets.
# The result is subtract(intersect(s, with), without),
# unless with is None, in which case it is subtract(s, without).
if with is None: with=s
d={}
tt=type(())
for i in s:
if type(i) is tt and len(i)==2: k, v = i
else: k= v = i
d[k]=v
r=[]
a=r.append
h=d.has_key
for i in without:
if type(i) is tt and len(i)==2: k, v = i
else: k= v = i
if h(k): del d[k]
for i in with:
if type(i) is tt and len(i)==2: k, v = i
else: k= v = i
if h(k):
a((k,d[k]))
del d[k]
return r
utility_builtins['reorder'] = reorder
=== Added File Zope3/lib/python/Zope/RestrictedPython/ZopeGuards.py ===
#############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
__version__='$Revision: 1.1.2.1 $'[11:-2]
from Zope.Exceptions import Unauthorized
from Zope.RestrictedPython.Guards import safe_builtins
from Zope.RestrictedPython.Utilities import utility_builtins
from Zope.App.Security.SecurityManagement import getSecurityManager
StringType = type('')
Containers = {list: 1, tuple: 1, dict: 1, str: 1, unicode: 1}.has_key
_marker = object() # Create a new marker object.
safe_builtins = safe_builtins.copy()
safe_builtins.update(utility_builtins)
def guarded_getattr(inst, name, default=_marker):
# Try to get the attribute normally so that unusual
# exceptions are caught early.
try: v = getattr(inst, name)
except AttributeError:
if default is not _marker:
return default
raise
if Containers(type(inst)):
# Simple type. Short circuit.
return v
getSecurityManager().validate(name, v)
return v
safe_builtins['getattr'] = guarded_getattr
def guarded_hasattr(object, name):
try:
guarded_getattr(object, name)
except (AttributeError, Unauthorized):
return 0
return 1
safe_builtins['hasattr'] = guarded_hasattr
SliceType = type(slice(0))
def guarded_getitem(object, index_or_key):
if isinstance(index_or_key, SliceType):
step = index_or_key.step
if step is not None and step != 1:
v = object[index_or_key]
else:
start = index_or_key.start
stop = index_or_key.stop
if start is None:
start = 0
if stop is None:
v = object[start:]
else:
v = object[start:stop]
# We don't guard slices.
return v
v = object[index_or_key]
if Containers(type(object)) and Containers(type(v)):
# Simple type. Short circuit.
return v
getSecurityManager().validate("#%s" % index_or_key, v)
return v
def guarded_filter(f, seq, skip_unauthorized=0):
if isinstance(seq, StringType):
return filter(f, seq)
if f is None:
def f(x): return x
validate = getSecurityManager().validate
result = []
append = result.append
for i in range(len(seq)):
el = seq[i]
try:
validate("#%d" % i, el)
except Unauthorized:
if skip_unauthorized:
pass
else:
raise
else:
if f(el):
append(el)
return result
safe_builtins['filter'] = guarded_filter
## from SecurityInfo import secureModule
## import sys
## def guarded_import(mname, globals={}, locals={}, fromlist=None):
## mnameparts = mname.split('.')
## firstmname = mnameparts[0]
## validate = getSecurityManager().validate
## module = load_module(None, None, mnameparts, validate, globals, locals)
## if module is not None:
## if fromlist is None:
## fromlist = ()
## try:
## for name in fromlist:
## if name == '*':
## raise ImportError, ('"from %s import *" is not allowed'
## % mname)
## v = getattr(module, name, None)
## if v is None:
## v = load_module(module, mname, [name], validate,
## globals, locals)
## validate(name, v)
## raise Unauthorized
## else:
## return __import__(mname, globals, locals, fromlist)
## except Unauthorized:
## raise ImportError, ('import of "%s" from "%s" is unauthorized'
## % (name, mname))
## raise ImportError, 'import of "%s" is unauthorized' % mname
## safe_builtins['__import__'] = guarded_import
## def load_module(module, mname, mnameparts, validate, globals, locals):
## modules = sys.modules
## while mnameparts:
## nextname = mnameparts.pop(0)
## if mname is None:
## mname = nextname
## else:
## mname = '%s.%s' % (mname, nextname)
## nextmodule = modules.get(mname)
## if nextmodule is None:
## nextmodule = secureModule(mname, globals, locals)
## if nextmodule is None:
## return
## else:
## secureModule(mname)
## if module is not None:
## # At the outer layer ("import foo"), there is no context
## # against which to validate.
## validate(nextname, nextmodule)
## module = nextmodule
## return module
=== Added File Zope3/lib/python/Zope/RestrictedPython/__init__.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
'''
RestrictedPython package.
$Id: __init__.py,v 1.1.2.1 2002/02/27 22:29:56 fdrake Exp $
'''
from RCompile import \
compile_restricted, \
compile_restricted_function, \
compile_restricted_exec, \
compile_restricted_eval
#from PrintCollector import PrintCollector