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

Merged RestrictedPython-2_2-branch.

parent e83fb023
...@@ -11,9 +11,9 @@ ...@@ -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([]) ListType = type([])
TupleType = 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 @@ ...@@ -11,7 +11,7 @@
# #
############################################################################## ##############################################################################
__version__='$Revision: 1.3 $'[11:-2] __version__='$Revision: 1.2 $'[11:-2]
import sys import sys
from traceback import format_exception_only from traceback import format_exception_only
...@@ -27,7 +27,7 @@ def getSyntaxError(source, mode): ...@@ -27,7 +27,7 @@ def getSyntaxError(source, mode):
return None, err, [], {} return None, err, [], {}
from parser import ParserError from parser import ParserError
from compiler.transformer import Transformer from compiler_2_1.transformer import Transformer
def tryParsing(source, mode): def tryParsing(source, mode):
if mode == 'eval': if mode == 'eval':
...@@ -41,7 +41,7 @@ def tryParsing(source, mode): ...@@ -41,7 +41,7 @@ def tryParsing(source, mode):
import MutatingWalker import MutatingWalker
from RestrictionMutator import RestrictionMutator 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): def compile_restricted_function(p, body, name, filename):
'''Compile a restricted code object for a function. '''Compile a restricted code object for a function.
......
...@@ -15,11 +15,9 @@ RestrictionMutator modifies a tree produced by ...@@ -15,11 +15,9 @@ RestrictionMutator modifies a tree produced by
compiler.transformer.Transformer, restricting and enhancing the compiler.transformer.Transformer, restricting and enhancing the
code in various ways before sending it to pycodegen. 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 SelectCompiler import ast, parse, OP_ASSIGN, OP_DELETE, OP_APPLY
from compiler.transformer import parse
from compiler.consts import OP_ASSIGN, OP_DELETE, OP_APPLY
# These utility functions allow us to generate AST subtrees without # These utility functions allow us to generate AST subtrees without
# line number attributes. These trees can then be inserted into other # line number attributes. These trees can then be inserted into other
...@@ -50,7 +48,9 @@ def exprNode(txt): ...@@ -50,7 +48,9 @@ def exprNode(txt):
# local, and therefore efficient to access, in function scopes. # local, and therefore efficient to access, in function scopes.
_print_target_name = ast.Name('_print') _print_target_name = ast.Name('_print')
_getattr_name = ast.Name('_getattr') _getattr_name = ast.Name('_getattr')
_getattr_name_expr = ast.Name('_getattr_')
_getitem_name = ast.Name('_getitem') _getitem_name = ast.Name('_getitem')
_getitem_name_expr = ast.Name('_getitem_')
_write_guard_name = ast.Name('_write') _write_guard_name = ast.Name('_write')
# Constants. # Constants.
...@@ -78,9 +78,11 @@ class FuncInfo: ...@@ -78,9 +78,11 @@ class FuncInfo:
_getattr_used = 0 _getattr_used = 0
_getitem_used = 0 _getitem_used = 0
_write_used = 0 _write_used = 0
_is_suite = 0 # True for modules and functions, false for expressions
class RestrictionMutator: class RestrictionMutator:
def __init__(self): def __init__(self):
self.funcinfo = FuncInfo() self.funcinfo = FuncInfo()
self.warnings = [] self.warnings = []
...@@ -113,6 +115,8 @@ class RestrictionMutator: ...@@ -113,6 +115,8 @@ class RestrictionMutator:
'because it starts with "_".' % name) 'because it starts with "_".' % name)
def prepBody(self, body): def prepBody(self, body):
"""Appends prep code to the beginning of a code suite.
"""
info = self.funcinfo info = self.funcinfo
if info._print_used or info._printed_used: if info._print_used or info._printed_used:
# Add code at top for creating _print_target # Add code at top for creating _print_target
...@@ -138,6 +142,7 @@ class RestrictionMutator: ...@@ -138,6 +142,7 @@ class RestrictionMutator:
former_funcinfo = self.funcinfo former_funcinfo = self.funcinfo
self.funcinfo = FuncInfo() self.funcinfo = FuncInfo()
self.funcinfo._is_suite = 1
node = walker.defaultVisitNode(node, exclude=('defaults',)) node = walker.defaultVisitNode(node, exclude=('defaults',))
self.prepBody(node.code.nodes) self.prepBody(node.code.nodes)
self.funcinfo = former_funcinfo self.funcinfo = former_funcinfo
...@@ -189,8 +194,11 @@ class RestrictionMutator: ...@@ -189,8 +194,11 @@ class RestrictionMutator:
#expr.append(_write_guard_name) #expr.append(_write_guard_name)
#self.funcinfo._write_used = 1 #self.funcinfo._write_used = 1
self.funcinfo._getattr_used = 1 self.funcinfo._getattr_used = 1
return ast.CallFunc(_getattr_name, if self.funcinfo._is_suite:
[node.expr, ast.Const(node.attrname)]) ga = _getattr_name
else:
ga = _getattr_name_expr
return ast.CallFunc(ga, [node.expr, ast.Const(node.attrname)])
def visitSubscript(self, node, walker): def visitSubscript(self, node, walker):
node = walker.defaultVisitNode(node) node = walker.defaultVisitNode(node)
...@@ -223,7 +231,11 @@ class RestrictionMutator: ...@@ -223,7 +231,11 @@ class RestrictionMutator:
if upper is None: if upper is None:
upper = _None_const upper = _None_const
subs = ast.Sliceobj([lower, upper]) 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): elif node.flags in (OP_DELETE, OP_ASSIGN):
# set or remove subscript or slice # set or remove subscript or slice
node.expr = ast.CallFunc(_write_guard_name, [node.expr]) node.expr = ast.CallFunc(_write_guard_name, [node.expr])
...@@ -251,6 +263,7 @@ class RestrictionMutator: ...@@ -251,6 +263,7 @@ class RestrictionMutator:
return walker.defaultVisitNode(node) return walker.defaultVisitNode(node)
def visitModule(self, node, walker): def visitModule(self, node, walker):
self.funcinfo._is_suite = 1
node = walker.defaultVisitNode(node) node = walker.defaultVisitNode(node)
self.prepBody(node.node.nodes) self.prepBody(node.node.nodes)
return node 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 @@ ...@@ -12,14 +12,9 @@
############################################################################## ##############################################################################
''' '''
RestrictedPython package. 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 \ from SelectCompiler import *
compile_restricted, \
compile_restricted_function, \
compile_restricted_exec, \
compile_restricted_eval
from PrintCollector import PrintCollector 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