cybertools/pyscript/script.py
helmutm 6960f85b8f added blank lines
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2020 fd906abe-77d9-0310-91a1-e0d9ade77398
2007-09-09 19:47:25 +00:00

175 lines
5.6 KiB
Python

##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (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.
#
##############################################################################
"""Python Page
$Id$
"""
__docformat__ = 'restructuredtext'
import new
import re
from cStringIO import StringIO
from persistent import Persistent
from zope.proxy import removeAllProxies
from zope.security.untrustedpython.builtins import SafeBuiltins
#from zope.security.untrustedpython.rcompile import compile
from zope.traversing.api import getParent, getPath
from zope.app.container.contained import Contained
from zope.interface import implements
from zope.app.i18n import ZopeMessageFactory as _
from cybertools.pyscript.interfaces import IPythonScript, IScriptContainer
import compiler.pycodegen
import RestrictedPython.RCompile
from RestrictedPython.SelectCompiler import ast
from zope.security.untrustedpython.rcompile import RestrictionMutator as BaseRM
unrestricted_objects = ('rpy', 'r', 'as_py')
def compile(text, filename, mode):
if not isinstance(text, basestring):
raise TypeError("Compiled source must be string")
gen = RExpression(text, str(filename), mode)
gen.compile()
return gen.getCode()
class RExpression(RestrictedPython.RCompile.RestrictedCompileMode):
CodeGeneratorClass = compiler.pycodegen.ExpressionCodeGenerator
def __init__(self, source, filename, mode = "eval"):
self.mode = mode
RestrictedPython.RCompile.RestrictedCompileMode.__init__(
self, source, filename)
self.rm = RestrictionMutator()
class RestrictionMutator(BaseRM):
unrestricted_objects = unrestricted_objects
def visitGetattr(self, node, walker):
_getattr_name = ast.Name("getattr")
node = walker.defaultVisitNode(node)
if node.expr.name in self.unrestricted_objects:
return node # no protection
return ast.CallFunc(_getattr_name,
[node.expr, ast.Const(node.attrname)])
class PythonScript(Contained, Persistent):
"""Persistent Python Page - Content Type
"""
implements(IPythonScript)
_v_compiled = None
def __init__(self, source=u'', contentType=u'text/plain'):
"""Initialize the object."""
super(PythonScript, self).__init__()
self.source = source
self.contentType = contentType
def __filename(self):
if self.__parent__ is None:
filename = 'N/A'
else:
filename = getPath(self)
return filename
def setSource(self, source):
"""Set the source of the page and compile it.
This method can raise a syntax error, if the source is not valid.
"""
self.__source = source
self.__prepared_source = self.prepareSource(source)
# Compile objects cannot be pickled
self._v_compiled = Function(self.__prepared_source, self.__filename())
_tripleQuotedString = re.compile(
r"^([ \t]*)[uU]?([rR]?)(('''|\"\"\")(.*)\4)", re.MULTILINE | re.DOTALL)
def prepareSource(self, source):
"""Prepare source."""
# compile() don't accept '\r' altogether
source = source.replace("\r\n", "\n")
source = source.replace("\r", "\n")
if isinstance(source, unicode):
# Use special conversion function to work around
# compiler-module failure to handle unicode in literals
try:
source = source.encode('ascii')
except UnicodeEncodeError:
return self._tripleQuotedString.sub(_print_usrc, source)
return self._tripleQuotedString.sub(r"\1print \2\3", source)
def getSource(self):
"""Get the original source code."""
return self.__source
source = property(getSource, setSource)
def __call__(self, request, **kw):
output = StringIO()
if self._v_compiled is None:
self._v_compiled = Function(self.__prepared_source,
self.__filename())
parent = getParent(self)
kw['request'] = request
kw['script'] = self
kw['untrusted_output'] = kw['printed'] = output
kw['context'] = parent
kw['script_result'] = None
if IScriptContainer.providedBy(parent):
parent.updateGlobals(kw)
self._v_compiled(kw)
result = kw['script_result']
if result == output:
result = result.getvalue().decode('unicode-escape')
return result
class Function(object):
"""A compiled function.
"""
def __init__(self, source, filename='<string>'):
lines = []
lines.insert(0, 'def dummy(): \n pass')
for line in source.splitlines():
lines.append(' ' + line)
lines.append('script_result = dummy()')
source = '\n'.join(lines)
#print source
self.code = compile(source, filename, 'exec')
def __call__(self, globals):
globals['__builtins__'] = SafeBuiltins
exec self.code in globals, None
def _print_usrc(match):
string = match.group(3)
raw = match.group(2)
if raw:
return match.group(1)+'print '+`string`
return match.group(1)+'print '+match.group(3).encode('unicode-escape')