[Zope3-checkins] CVS: Zope3/src/zope/app/pythonpage - MAINTAINER.txt:1.2 README.txt:1.2 __init__.py:1.2 browser.py:1.2 configure.zcml:1.2 edit.pt:1.2 tests.py:1.2 version.txt:1.2

Philipp von Weitershausen philikon at philikon.de
Tue Feb 24 11:50:29 EST 2004


Update of /cvs-repository/Zope3/src/zope/app/pythonpage
In directory cvs.zope.org:/tmp/cvs-serv27021/src/zope/app/pythonpage

Added Files:
	MAINTAINER.txt README.txt __init__.py browser.py 
	configure.zcml edit.pt tests.py version.txt 
Log Message:


Moved the pythonpage package from zope.products to zope.app. Nothing
else has changed except for the imports.




=== Zope3/src/zope/app/pythonpage/MAINTAINER.txt 1.1 => 1.2 ===
--- /dev/null	Tue Feb 24 11:50:29 2004
+++ Zope3/src/zope/app/pythonpage/MAINTAINER.txt	Tue Feb 24 11:50:28 2004
@@ -0,0 +1,5 @@
+Stephan Richter
+
+  Email: stephan.richter at tufts.edu
+
+  IRC nick: srichter
\ No newline at end of file


=== Zope3/src/zope/app/pythonpage/README.txt 1.1 => 1.2 ===
--- /dev/null	Tue Feb 24 11:50:29 2004
+++ Zope3/src/zope/app/pythonpage/README.txt	Tue Feb 24 11:50:28 2004
@@ -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::
+
+  '''
+  <html>
+    <body>
+      <ul>
+  '''
+
+  import time
+  print time.asctime()
+
+  '''
+      </ul>
+    </body>
+  </html>
+  '''


=== Zope3/src/zope/app/pythonpage/__init__.py 1.1 => 1.2 ===
--- /dev/null	Tue Feb 24 11:50:29 2004
+++ Zope3/src/zope/app/pythonpage/__init__.py	Tue Feb 24 11:50:28 2004
@@ -0,0 +1,182 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Python Page
+
+$Id$
+"""
+import re
+from persistent import Persistent
+from zope.app import zapi
+from zope.app.container.contained import Contained
+from zope.interface import Interface, implements
+from zope.schema import SourceText, TextLine
+from zope.app.i18n import ZopeMessageIDFactory as _
+
+triple_quotes_start = re.compile('^[ \t]*("""|\'\'\')', re.MULTILINE) 
+single_triple_quotes_end = re.compile("'''") 
+double_triple_quotes_end = re.compile('"""') 
+
+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 = SourceText(
+        title=_("Source"),
+        description=_("The source of the Python page."),
+        required=False)
+
+    contentType = TextLine(
+        title=_("Content Type"),
+        description=_("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.
+        """
+
+
+class PythonPage(Contained, Persistent):
+    r"""Persistent Python Page - Content Type
+
+    Examples::
+
+      >>> from tests import setUp, tearDown, Root
+      >>> setUp()
+
+      >>> pp = PythonPage()
+      >>> pp.__parent__ = Root()
+      >>> pp.__name__ = 'pp'
+      >>> request = None
+
+      >>> pp.setSource(u"'''<html>...</html>'''")
+      >>> pp(request)
+      u'<html>...</html>\n'
+
+      >>> pp.setSource(u"if 1 == 1:\n   '''<html>...</html>'''")
+      >>> pp(request)
+      u'<html>...</html>\n'
+
+      >>> pp.setSource(u"print u'<html>...</html>'")
+      >>> pp(request)
+      u'<html>...</html>\n'
+
+      >>> pp.setSource(u"'''<html>%s</html>''' %x")
+      >>> pp(request, x='test')
+      u'<html>test</html>\n'
+
+      >>> pp.setSource(u"'''<html>%s</html>''' %context.__name__")
+      >>> pp(request)
+      u'<html>root</html>\n'
+
+      >>> try:
+      ...     pp.setSource(u"'''<html>...</html>") #'''"
+      ... except SyntaxError, err:
+      ...     print err
+      No matching closing quotes found. (line 1)
+
+      >>> try:
+      ...     pp.setSource(u"prin 'hello'")
+      ... except SyntaxError, err:
+      ...     print err
+      invalid syntax (pp, line 1)
+
+      >>> tearDown()
+    """
+
+    implements(IPythonPage)
+
+    def __init__(self, source=u'', contentType=u'text/html'):
+        """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 = zapi.getPath(self)
+        return filename
+        
+    def setSource(self, source):
+        r"""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
+        
+        source = source.encode('utf-8')
+        start = 0
+        match = triple_quotes_start.search(source, start)
+        while match:
+            open = match.group()
+            source = source[:match.end()-3] + 'print u' + \
+                     source[match.end()-3:]
+            start = match.end() + 7
+            
+            # Now let's find the end of the quote
+            if match.group().endswith('"""'):
+                end = double_triple_quotes_end.search(source, start)
+            else:
+                end = single_triple_quotes_end.search(source, start)
+
+            if end is None:
+                lineno = len(source[:start].split('\n'))
+                offset = len(match.group())
+                raise SyntaxError(
+                    'No matching closing quotes found.',
+                    (self.__filename(), lineno, offset, match.group()))
+
+            start = end.end()    
+            match = triple_quotes_start.search(source, start)        
+
+        self.__prepared_source = source
+
+        # Compile objects cannot be pickled
+        self._v_compiled = compile(self.__prepared_source, self.__filename(),
+                                   'exec')
+
+    def getSource(self):
+        """Get the original source code."""
+        return self.__source
+        
+    # See IPage
+    source = property(getSource, setSource)
+
+
+    def __call__(self, request, **kw):
+        """See IPythonPage"""
+
+        # Compile objects cannot be pickled
+        if not hasattr(self, '_v_compiled'):
+            self._v_compiled = compile(self.__prepared_source,
+                                       self.__filename(), 'exec')
+
+        kw['request'] = request
+        kw['script'] = self
+        kw['context'] = zapi.getParent(self)
+
+        service = zapi.queryService(self, 'Interpreter')
+        interpreter = service.queryInterpreter('text/server-python')
+        return interpreter.evaluate(self._v_compiled, kw)


=== Zope3/src/zope/app/pythonpage/browser.py 1.1 => 1.2 ===
--- /dev/null	Tue Feb 24 11:50:29 2004
+++ Zope3/src/zope/app/pythonpage/browser.py	Tue Feb 24 11:50:28 2004
@@ -0,0 +1,46 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Python Page Browser Views 
+
+$Id$
+"""
+from zope.app.browser.form.editview import EditView
+from zope.app.i18n import ZopeMessageIDFactory as _
+
+class PythonPageEval:
+    """Evaluate the Python Page."""
+
+    def index(self, **kw):
+        """Call a Python Page"""
+
+        self.request.response.setHeader('content-type',
+                                        self.context.contentType)
+
+        return 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 occured.')
+            self.update_status = status
+
+        return status


=== Zope3/src/zope/app/pythonpage/configure.zcml 1.1 => 1.2 ===
--- /dev/null	Tue Feb 24 11:50:29 2004
+++ Zope3/src/zope/app/pythonpage/configure.zcml	Tue Feb 24 11:50:28 2004
@@ -0,0 +1,79 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zope">
+
+  <interface 
+      interface=".IPythonPage" 
+      type="zope.app.interfaces.content.IContentType"
+      /> 
+  
+  <content class=".PythonPage">
+  
+    <factory
+        id="zope.app.pythonpage.PythonPage"
+        permission="zope.ManageContent"
+        title="Python Page"
+        description="A simple, content-based Python Page"
+        />
+  
+    <require
+        permission="zope.View"
+        interface=".IPythonPage"
+        />
+  
+    <require
+        permission="zope.ManageContent"
+        set_attributes="source contentType"
+        />
+  
+    <implements
+        interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
+  
+  </content>
+
+
+  <!-- browser directives -->
+
+  <browser:page
+      name="index.html"
+      for=".IPythonPage"
+      class=".browser.PythonPageEval"
+      attribute="index"
+      permission="zope.View"
+      />
+
+  <browser:addform
+      label="Add Python Page"
+      name="AddPythonPage"
+      schema=".IPythonPage"
+      content_factory=".PythonPage"
+      permission="zope.ManageContent"
+      menu="add_content" title="Python Page"
+      />
+
+  <browser:editform
+      for=".IPythonPage"
+      schema=".IPythonPage"
+      name="edit.html"
+      label="Edit Python Page"
+      class=".browser.PythonPageEditView"
+      template="edit.pt"
+      permission="zope.ManageContent" 
+      menu="zmi_views" title="Edit"
+      />
+
+
+  <!-- Preview view - requires zope.app.preview -->
+
+  <configure package="zope.app.preview">
+    <browser:page
+        for="zope.app.pythonpage.IPythonPage"
+        name="preview.html"
+        template="preview.pt"
+        permission="zope.ManageContent"
+        menu="zmi_views" title="Preview"
+        />
+  </configure>
+
+</configure>
\ No newline at end of file


=== Zope3/src/zope/app/pythonpage/edit.pt 1.1 => 1.2 ===
--- /dev/null	Tue Feb 24 11:50:29 2004
+++ Zope3/src/zope/app/pythonpage/edit.pt	Tue Feb 24 11:50:28 2004
@@ -0,0 +1,90 @@
+<tal:tag condition="view/update"/>
+<html metal:use-macro="views/standard_macros/page">
+  <body>
+  <div metal:fill-slot="body">
+
+  <div metal:define-macro="body">
+
+    <form action="." tal:attributes="action request/URL" method="POST"
+          enctype="multipart/form-data">
+
+      <div metal:define-macro="formbody">
+
+        <h3 tal:condition="view/label"
+            tal:content="view/label"
+            metal:define-slot="heading"
+            >Edit something</h3>
+
+        <p tal:define="status view/update"
+           tal:condition="status"
+           tal:content="status" />
+
+        <p tal:condition="view/errors" i18n:translate="">
+          There are  <strong tal:content="python:len(view.errors)"
+                             i18n:name="num_errors">6</strong> input errors.
+        </p>
+
+        <div class="message"
+           tal:condition="view/syntaxError"
+           tal:define="err view/syntaxError">
+          <h3 i18n:translate="">Syntax Error: 
+            <span tal:content="err/msg" i18n:name="msg">invalid syntax</span>
+          </h3>
+          <div i18n:translate="">
+            File 
+            "<span tal:replace="err/filename" i18n:name="filename">
+               filename
+            </span>",
+            line <span tal:replace="err/lineno" i18n:name="lineno">10</span>,
+            offset <span tal:replace="err/offset" i18n:name="offset">1</span>
+          </div>
+          <pre tal:content="python:err.text+'\n'+' '*err.offset+'^'">
+             prin "foo"
+                 ^
+          </pre>
+        </div>
+
+        <div metal:define-slot="extra_info" tal:replace="nothing">
+        </div>
+
+        <div class="row"
+             metal:define-slot="extra_top" tal:replace="nothing">
+            <div class="label">Extra top</div>
+            <div class="field"><input type="text" style="width:100%" /></div>
+        </div>
+        <div class="row"
+             metal:define-macro="widget_rows" tal:repeat="widget view/widgets"
+             tal:content="structure widget/row">
+            <div class="label">Name</div>
+            <div class="field"><input type="text" style="width:100%" /></div>
+        </div>
+        <div class="separator"></div>
+        <div class="row"
+             metal:define-slot="extra_bottom" tal:replace="nothing">
+            <div class="label">Extra bottom</div>
+            <div class="field"><input type="text" style="width:100%" /></div>
+        </div>
+        <div class="separator"></div>
+      </div>
+
+      <div class="row">
+        <div class="controls">
+          <input type="submit" value="Refresh" 
+              i18n:attributes="value refresh-button" />
+          <input type="submit" name="UPDATE_SUBMIT" value="Change" 
+              i18n:attributes="value submit-button"/>
+        </div>
+      </div>
+      <div class="row" metal:define-slot="extra_buttons" tal:replace="nothing">
+      </div>
+
+      <div class="separator"></div>
+
+    </form>
+
+  </div>
+
+  </div>
+  </body>
+
+</html>


=== Zope3/src/zope/app/pythonpage/tests.py 1.1 => 1.2 ===
--- /dev/null	Tue Feb 24 11:50:29 2004
+++ Zope3/src/zope/app/pythonpage/tests.py	Tue Feb 24 11:50:28 2004
@@ -0,0 +1,64 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Tests for Python Page
+
+$Id$
+"""
+import unittest
+from zope.app import zapi
+from zope.app.container.contained import Contained
+from zope.app.interfaces.interpreter import IInterpreter, IInterpreterService
+from zope.app.interfaces.traversing import IContainmentRoot
+from zope.app.interfaces.traversing import IPhysicallyLocatable
+from zope.app.interpreter import interpreterService
+from zope.app.interpreter.python import PythonInterpreter
+from zope.app.location import LocationPhysicallyLocatable
+from zope.app.tests import placelesssetup, ztapi
+from zope.app.traversing.adapters import RootPhysicallyLocatable
+from zope.component.servicenames import Services
+from zope.interface import implements
+from zope.testing.doctestunit import DocTestSuite
+
+
+class Root(Contained):
+    implements(IContainmentRoot)    
+
+    __parent__ = None
+    __name__ = 'root'
+
+def setUp():
+    placelesssetup.setUp()
+    interpreterService.provideInterpreter('text/server-python',
+                                          PythonInterpreter)
+    services = zapi.getService(None, Services)
+    services.defineService('Interpreter', IInterpreterService)
+    services.provideService('Interpreter', interpreterService)
+
+    ztapi.provideAdapter(None, IPhysicallyLocatable,
+                         LocationPhysicallyLocatable)
+    ztapi.provideAdapter(IContainmentRoot, IPhysicallyLocatable,
+                         RootPhysicallyLocatable)
+    
+
+def tearDown():
+    placelesssetup.tearDown()
+
+    
+def test_suite():
+    return unittest.TestSuite((
+        DocTestSuite('zope.app.pythonpage'),
+        ))
+
+if __name__ == '__main__':
+    unittest.main()


=== Zope3/src/zope/app/pythonpage/version.txt 1.1 => 1.2 ===
--- /dev/null	Tue Feb 24 11:50:29 2004
+++ Zope3/src/zope/app/pythonpage/version.txt	Tue Feb 24 11:50:28 2004
@@ -0,0 +1 @@
+PythonPage 0.1
\ No newline at end of file




More information about the Zope3-Checkins mailing list