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

Stephan Richter srichter at cosmos.phy.tufts.edu
Fri Jan 30 18:19:25 EST 2004


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

Added Files:
	MAINTAINER.txt README.txt __init__.py browser.py 
	configure.zcml edit.pt preview.pt tests.py version.txt 
Log Message:
Took Casey's word and implemented a Python Page based on Casey's example.
See the README.txt and the PythonPage doc string for some examples.


=== Added File Zope3/src/zope/products/pythonpage/MAINTAINER.txt ===
Stephan Richter

  Email: stephan.richter at tufts.edu

  IRC nick: srichter

=== Added File Zope3/src/zope/products/pythonpage/README.txt ===
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.


Installation
------------

  1. In your 'products.zcml' file make sure that  you register this product 
     using::

       <include package="zope.products.pythonpage"/>

  2. Restart Zope 3.

  3. You can now create a new content type called "Python Page". Try the
     following source::

       '''
       <html>
         <body>
           <ul>
       '''
       
       import time
       print time.asctime()
       
       '''
           </ul>
         </body>
       </html>
       '''





=== Added File Zope3/src/zope/products/pythonpage/__init__.py ===
##############################################################################
#
# 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: __init__.py,v 1.1 2004/01/30 23:19:23 srichter Exp $
"""
import re
from persistence 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)

    content_type = 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'', content_type=u'text/html'):
        """Initialize the object."""
        super(PythonPage, self).__init__()
        self.source = source
        self.content_type = content_type

    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)


=== Added File Zope3/src/zope/products/pythonpage/browser.py ===
##############################################################################
#
# 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: browser.py,v 1.1 2004/01/30 23:19:23 srichter Exp $
"""
from zope.app.browser.form.editview import EditView

class PythonPageEval:
    """Evaluate the Python Page."""

    def index(self, **kw):
        """Call a Python Page"""

        self.request.response.setHeader('content-type',
                                        self.context.content_type)
        
        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 = u'A syntax error occured.'
            self.update_status = status

        return status

        


=== Added File Zope3/src/zope/products/pythonpage/configure.zcml ===
<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.products.pythonpaeg.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 content_type" />
  
    <implements
        interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
  
  </content>

  <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"/>

  <browser:page
      for=".IPythonPage"
      name="preview.html"
      menu="zmi_views" title="Preview"
      template="preview.pt"
      permission="zope.ManageContent" />

</configure>

=== Added File Zope3/src/zope/products/pythonpage/edit.pt ===
<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>Syntax Error: 
            <span tal:content="err/msg">invalid syntax</span>
          </h3>
          <div>
            File "<span tal:replace='err/filename'>filename</span>",
            line <span tal:replace="err/lineno">10</span>,
            offset <span tal:replace="err/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>


=== Added File Zope3/src/zope/products/pythonpage/preview.pt ===
<html metal:use-macro="views/standard_macros/page">
<body>
<div metal:fill-slot="body">

  <iframe src="." height="98%" width="98%"></iframe>

</div>
</body>
</html>


=== Added File Zope3/src/zope/products/pythonpage/tests.py ===
##############################################################################
#
# 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: tests.py,v 1.1 2004/01/30 23:19:23 srichter Exp $
"""
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.products.pythonpage'),
        ))

if __name__ == '__main__':
    unittest.main()


=== Added File Zope3/src/zope/products/pythonpage/version.txt ===
PythonPage 0.1



More information about the Zope3-Checkins mailing list