 6960f85b8f
			
		
	
	
		6960f85b8f
		
	
	
	
	
		
			
			git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2020 fd906abe-77d9-0310-91a1-e0d9ade77398
		
			
				
	
	
		
			175 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			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')
 |