[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