diff --git a/pyscript/README.txt b/pyscript/README.txt
new file mode 100644
index 0000000..ca4daa5
--- /dev/null
+++ b/pyscript/README.txt
@@ -0,0 +1,29 @@
+Python Page
+===========
+
+Python Page provides the user with a content object that interprets
+Python in content space. To save typing and useless messing with
+output, any free-standing string and print statement are considered
+for output; see the example below.
+
+
+Example
+-------
+
+Create a new content type called "Python Page" and enter the following
+code example::
+
+ '''
+
+
+
+ '''
+
+ import time
+ print time.asctime()
+
+ '''
+
+
+
+ '''
diff --git a/pyscript/__init__.py b/pyscript/__init__.py
new file mode 100644
index 0000000..38314f3
--- /dev/null
+++ b/pyscript/__init__.py
@@ -0,0 +1,3 @@
+"""
+$Id$
+"""
diff --git a/pyscript/browser.py b/pyscript/browser.py
new file mode 100644
index 0000000..dcc1777
--- /dev/null
+++ b/pyscript/browser.py
@@ -0,0 +1,47 @@
+##############################################################################
+#
+# 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 Browser Views
+
+$Id$
+"""
+
+from zope.app.form.browser.editview import EditView
+from zope.app.i18n import ZopeMessageFactory as _
+
+
+class PythonPageEval(object):
+ """Evaluate the Python Page."""
+
+ def index(self, **kw):
+ """Call a Python Page"""
+ self.request.response.setHeader('content-type',
+ self.context.contentType)
+ return str(self.context(self.request, **kw))
+
+
+class PythonPageEditView(EditView):
+ """Edit View Class for Python Page."""
+
+ syntaxError = None
+
+ def update(self):
+ """Update the content with the HTML form data."""
+ try:
+ status = super(PythonPageEditView, self).update()
+ except SyntaxError, err:
+ self.syntaxError = err
+ status = _('A syntax error occurred.')
+ self.update_status = status
+
+ return status
diff --git a/pyscript/configure.zcml b/pyscript/configure.zcml
new file mode 100644
index 0000000..a4783a7
--- /dev/null
+++ b/pyscript/configure.zcml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pyscript/cybertools.pyscript-configure.zcml b/pyscript/cybertools.pyscript-configure.zcml
new file mode 100644
index 0000000..fea2eb0
--- /dev/null
+++ b/pyscript/cybertools.pyscript-configure.zcml
@@ -0,0 +1 @@
+
diff --git a/pyscript/edit.pt b/pyscript/edit.pt
new file mode 100644
index 0000000..68d434a
--- /dev/null
+++ b/pyscript/edit.pt
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
diff --git a/pyscript/interfaces.py b/pyscript/interfaces.py
new file mode 100644
index 0000000..0f11a0c
--- /dev/null
+++ b/pyscript/interfaces.py
@@ -0,0 +1,57 @@
+#
+# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+"""
+interface definitions for the pyscript package.
+
+$Id$
+"""
+
+from zope.interface import Interface
+from zope import schema
+
+
+class IPythonPage(Interface):
+ """Python Page
+
+ The Python Page acts as a simple content type that allows you to execute
+ Python in content space. Additionally, if you have a free-standing
+ triple-quoted string, it gets converted to a print statement
+ automatically.
+ """
+
+ source = schema.SourceText(
+ title=_(u"Source"),
+ description=_(u"The source of the Python page."),
+ required=True,
+ )
+
+ contentType = schema.TextLine(
+ title=_(u"Content Type"),
+ description=_(u"The content type the script outputs."),
+ required=True,
+ default=u"text/html",
+ )
+
+ def __call__(request, **kw):
+ """Execute the script.
+
+ The script will insert the `request` and all `**kw` as global
+ variables. Furthermore, the variables `script` and `context` (which is
+ the container of the script) will be added.
+ """
diff --git a/pyscript/script.py b/pyscript/script.py
new file mode 100644
index 0000000..7af5bd5
--- /dev/null
+++ b/pyscript/script.py
@@ -0,0 +1,136 @@
+##############################################################################
+#
+# 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.app.interpreter.interfaces import IInterpreter
+from zope.interface import implements
+from zope.app.i18n import ZopeMessageFactory as _
+
+from cybertools.pyscript.interfaces import IPythonPage
+
+
+class PythonPage(Contained, Persistent):
+ """Persistent Python Page - Content Type
+ """
+
+ implements(IPythonPage)
+
+ _v_compiled = None
+
+ def __init__(self, source=u'', contentType=u'text/plain'):
+ """Initialize the object."""
+ super(PythonPage, 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 u\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())
+ kw['request'] = request
+ kw['script'] = self
+ kw['untrusted_output'] = output
+ kw['printed'] = output
+ kw['context'] = getParent(self)
+ kw['script_result'] = None
+ self._v_compiled(kw)
+ result = kw['script_result']
+ if result == output:
+ result = result.getvalue()
+ return result
+
+
+class Function(object):
+ """A compiled function.
+ """
+
+ def __init__(self, source, filename=''):
+ lines = []
+ lines.insert(0, 'def dummy():')
+ 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
+ #fct = new.function(self.code, globals)
+ exec self.code in globals, None
+ #return fct()
+
+
+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 u'+match.group(3).encode('unicode-escape')
diff --git a/pyscript/tests.py b/pyscript/tests.py
new file mode 100644
index 0000000..bd4495b
--- /dev/null
+++ b/pyscript/tests.py
@@ -0,0 +1,58 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Tests for Python Page
+
+$Id$
+"""
+import unittest
+
+import zope.component
+from zope.interface import implements
+from zope.testing.doctestunit import DocTestSuite
+from zope.traversing.interfaces import IContainmentRoot
+from zope.traversing.interfaces import IPhysicallyLocatable
+from zope.traversing.adapters import RootPhysicallyLocatable
+from zope.location.traversing import LocationPhysicallyLocatable
+
+from zope.app.container.contained import Contained
+#from zope.app.interpreter.interfaces import IInterpreter
+#from zope.app.interpreter.python import PythonInterpreter
+from zope.app.testing import placelesssetup, ztapi
+
+class Root(Contained):
+ implements(IContainmentRoot)
+
+ __parent__ = None
+ __name__ = 'root'
+
+def setUp(test):
+ placelesssetup.setUp()
+ sm = zope.component.getGlobalSiteManager()
+ #sm.registerUtility(PythonInterpreter, IInterpreter, 'text/server-python')
+
+ ztapi.provideAdapter(None, IPhysicallyLocatable,
+ LocationPhysicallyLocatable)
+ ztapi.provideAdapter(IContainmentRoot, IPhysicallyLocatable,
+ RootPhysicallyLocatable)
+
+
+
+def test_suite():
+ return unittest.TestSuite((
+ DocTestSuite('cybertools.pyscript',
+ setUp=setUp, tearDown=placelesssetup.tearDown),
+ ))
+
+if __name__ == '__main__':
+ unittest.main()