Commit 647378bf authored by Shane Hathaway's avatar Shane Hathaway

Merged RestrictedPython-2_2-branch.

parent e83fb023
......@@ -11,9 +11,9 @@
#
##############################################################################
__version__='$Revision: 1.4 $'[11:-2]
__version__='$Revision: 1.5 $'[11:-2]
from compiler import ast
from SelectCompiler import ast
ListType = type([])
TupleType = type(())
......
##############################################################################
#
# 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.2 $'[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()
......@@ -11,7 +11,7 @@
#
##############################################################################
__version__='$Revision: 1.3 $'[11:-2]
__version__='$Revision: 1.2 $'[11:-2]
import sys
from traceback import format_exception_only
......@@ -27,7 +27,7 @@ def getSyntaxError(source, mode):
return None, err, [], {}
from parser import ParserError
from compiler.transformer import Transformer
from compiler_2_1.transformer import Transformer
def tryParsing(source, mode):
if mode == 'eval':
......@@ -41,7 +41,7 @@ def tryParsing(source, mode):
import MutatingWalker
from RestrictionMutator import RestrictionMutator
from compiler import ast, visitor, pycodegen
from compiler_2_1 import ast, visitor, pycodegen
def compile_restricted_function(p, body, name, filename):
'''Compile a restricted code object for a function.
......
......@@ -15,11 +15,9 @@ 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.8 $'[11:-2]
__version__='$Revision: 1.9 $'[11:-2]
from compiler import ast
from compiler.transformer import parse
from compiler.consts import OP_ASSIGN, OP_DELETE, OP_APPLY
from SelectCompiler import ast, parse, 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
......@@ -50,7 +48,9 @@ def exprNode(txt):
# 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.
......@@ -78,9 +78,11 @@ class FuncInfo:
_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 = []
......@@ -113,6 +115,8 @@ class RestrictionMutator:
'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
......@@ -138,6 +142,7 @@ class RestrictionMutator:
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
......@@ -189,8 +194,11 @@ class RestrictionMutator:
#expr.append(_write_guard_name)
#self.funcinfo._write_used = 1
self.funcinfo._getattr_used = 1
return ast.CallFunc(_getattr_name,
[node.expr, ast.Const(node.attrname)])
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)
......@@ -223,7 +231,11 @@ class RestrictionMutator:
if upper is None:
upper = _None_const
subs = ast.Sliceobj([lower, upper])
return ast.CallFunc(_getitem_name, [node.expr, subs])
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])
......@@ -251,6 +263,7 @@ class RestrictionMutator:
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
......
##############################################################################
#
# 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
#
##############################################################################
'''
Compiler selector.
$Id: SelectCompiler.py,v 1.2 2001/12/21 19:34:47 shane Exp $
'''
try:
import compiler # Should only be found if Python >= 2.2.
except ImportError:
# Use the compiler_2_1 package.
from compiler_2_1 import ast
from compiler_2_1.transformer import parse
from compiler_2_1.consts import OP_ASSIGN, OP_DELETE, OP_APPLY
from RCompile_2_1 import \
compile_restricted, \
compile_restricted_function, \
compile_restricted_exec, \
compile_restricted_eval
else:
# Use the compiler from the standard library.
from compiler import ast
from compiler.transformer import parse
from compiler.consts import OP_ASSIGN, OP_DELETE, OP_APPLY
from RCompile import \
compile_restricted, \
compile_restricted_function, \
compile_restricted_exec, \
compile_restricted_eval
......@@ -12,14 +12,9 @@
##############################################################################
'''
RestrictedPython package.
$Id: __init__.py,v 1.3 2001/11/28 15:51:11 matt Exp $
$Id: __init__.py,v 1.4 2001/12/21 19:34:47 shane Exp $
'''
from Compilers import \
compile_restricted, \
compile_restricted_function, \
compile_restricted_exec, \
compile_restricted_eval
from SelectCompiler import *
from PrintCollector import PrintCollector
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