[Zope-Checkins] CVS: Packages/OFS - Examples.py:1.1.2.1 Application.py:1.160.12.1 Folder.py:1.96.12.1

Evan Simpson evan@zope.com
Tue, 13 Nov 2001 14:39:02 -0500


Update of /cvs-repository/Packages/OFS
In directory cvs.zope.org:/tmp/cvs-serv25062/OFS

Modified Files:
      Tag: evan-examples-branch
	Application.py Folder.py 
Added Files:
      Tag: evan-examples-branch
	Examples.py 
Log Message:
Make formerly reserved objects in the root into shadow objects that are
available even when deleted, and are re-created at startup.

Add standard_template.pt for ZPT.

Add "Examples..." to add lists, which scans for Products with 'examples'
directories with a 'index.xml' manifest file.  See Products/PageTemplates
for an example of this.


=== Added File Packages/OFS/Examples.py ===
##############################################################################
# 
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
# 
# Copyright (c) Digital Creations.  All rights reserved.
# 
# This license has been certified as Open Source(tm).
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 
# 1. Redistributions in source code must retain the above copyright
#    notice, this list of conditions, and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions, and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
# 
# 3. Digital Creations requests that attribution be given to Zope
#    in any manner possible. Zope includes a "Powered by Zope"
#    button that is installed by default. While it is not a license
#    violation to remove this button, it is requested that the
#    attribution remain. A significant investment has been put
#    into Zope, and this effort will continue if the Zope community
#    continues to grow. This is one way to assure that growth.
# 
# 4. All advertising materials and documentation mentioning
#    features derived from or use of this software must display
#    the following acknowledgement:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    In the event that the product being advertised includes an
#    intact Zope distribution (with copyright and license included)
#    then this clause is waived.
# 
# 5. Names associated with Zope or Digital Creations must not be used to
#    endorse or promote products derived from this software without
#    prior written permission from Digital Creations.
# 
# 6. Modified redistributions of any form whatsoever must retain
#    the following acknowledgment:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    Intact (re-)distributions of any official Zope release do not
#    require an external acknowledgement.
# 
# 7. Modifications are encouraged but must be packaged separately as
#    patches to official Zope releases.  Distributions that do not
#    clearly separate the patches from the original work must be clearly
#    labeled as unofficial distributions.  Modifications which do not
#    carry the name Zope may be packaged in any form, as long as they
#    conform to all of the clauses above.
# 
# 
# Disclaimer
# 
#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#   SUCH DAMAGE.
# 
# 
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations.  Specific
# attributions are listed in the accompanying credits file.
# 
##############################################################################

"""Examples mixin

Provide support for Product examples.

$Id: Examples.py,v 1.1.2.1 2001/11/13 19:39:00 evan Exp $"""

__version__='$Revision: 1.1.2.1 $'[11:-2]

import os, sys, Shared.DC.xml.xmllib
from Globals import DTMLFile
from AccessControl import getSecurityManager
from ObjectManager import ObjectManager
import OFS.Application, StructuredText
from zLOG import LOG, ERROR
from cgi import escape

class Examples:
    meta_types = ObjectManager.meta_types + (
        {'permission': 'View management interface',
         'name': ' Example...',
         'action': 'manage_product_examples'},
        )

    _product_examplesForm=DTMLFile('dtml/product_examples', globals())

    def manage_product_examples(self, REQUEST, RESPONSE):
        """Handle display and use of Product examples."""
        chosen = REQUEST.form.get('example')
        if chosen:
            example = self._get_product_example(chosen)
            # Do example
            for act, path in example['actions']:
                if act == 'import':
                    self._importObjectFromFile(
                        os.path.join(example['dir'], path))
                elif act == 'execute':
                    execfile(os.path.join(example['dir'], path), {})
                elif act == 'call':
                    self.unrestrictedTraverse(path)()
            if example['view']:
                RESPONSE.redirect(example['view'])
            return self.manage_main(self, REQUEST, 
                manage_tabs_message="Example %s chosen." % chosen,
                title = 'Example chosen',
                update_menu=1)
        examples = self._get_product_examples()
        return self._product_examplesForm(examples=examples)

    def _get_product_examples(self):
        all_examples = []
        for priority, name, i, product_dir in OFS.Application.get_products():
            dir = os.path.join(product_dir, name, 'examples')
            if not os.path.isdir(dir):
                continue
            fn = os.path.join(dir, 'index.xml')
            if not os.path.isfile(fn):
                continue
            try:
                examples = XmlParser().parse(open(fn).read())
            except (ExampleError, RuntimeError):
                LOG("Examples", ERROR, fn, error=sys.exc_info())
            else:
                all_examples.append((name, examples))
        return all_examples

    def _get_product_example(self, name):
        pname, ename = name.split('.', 1)
        for priority, name, i, product_dir in OFS.Application.get_products():
            if name != pname:
                continue
            dir = os.path.join(product_dir, name, 'examples')
            fn = os.path.join(dir, 'index.xml')
            if not os.path.isfile(fn):
                break
            try:
                examples = XmlParser().parse(open(fn).read())
            except (ExampleError, RuntimeError):
                LOG("Examples", ERROR, fn, error=sys.exc_info())
            else:
                for example in examples:
                    if example['name'] != ename:
                        continue
                    example['dir'] = dir
                    return example
            break
        raise ExampleError, "Example %s not found." % `name`

class ExampleError(Exception):
    pass

# Simple XML parser for manifest files

class Node:
    allowed_children = ()
    def __init__(self, name, attrs):
        self.name = name
        self.attrs = attrs
        self.start()

    def start(self):
        self.data = []

    def end(self, name):
        if name == self.name:
            return 1
        raise ExampleError, "Improperly closed %s" % self.name

    def add(self, node):
        raise ExampleError, "%s should not have child nodes" % self.name

    def addData(self, data, cdata=0):
        self.data.append(data)

    def noData(self, data, cdata=0):
        if data.strip():
            raise ExampleError, "%s should not have text" % self.name

    def noAttrs(self):
        if self.attrs:
            raise ExampleError, "%s should not have attributes" % self.name

    def getReqAttr(self, attrname):
        try:
            return self.attrs[attrname]
        except KeyError:
            raise ExampleError, ("%s missing required attribute %s" %
                                   (self.name, attrname))

class RootNode:
    allowed_children = ('example',)
    def __init__(self):
        self.examples = []
    def add(self, node):
        self.examples.append(node)
    def addData(self, data, cdata=0):
        pass
    def out(self):
        ex = []
        for example in self.examples:
            ex.append({'name': example.getReqAttr('name'),
                       'description': example.description,
                       'actions': example.actions,
                       'view': example.view})
        return ex

class ExampleNode(Node):
    allowed_children = ('description', 'payload', 'view')
    description = None
    view = None
    def start(self):
        self.payload = []
    def add(self, node):
        if node.name =='payload':
            node.payload = self.payload
        else:
            if getattr(self, node.name, None) is not None:
                raise ExampleError, "Only one %s allowed" % node.name
            setattr(self, node.name, node)
    def end(self, name):
        if self.view is not None:
            self.view = self.view.getReqAttr('url')
        if self.description is not None:
            text = ''.join(self.description.data)
            format = self.description.attrs.get('format', 'plain')
            if format == 'plain':
                text = escape(text)
            elif format == 'stx':
                text = StructuredText.HTMLNG(
                    StructuredText.Basic(text), header=0)
            elif format != 'html':
                raise ExampleError, "Unknown description format %s" % format
            self.description = text
        self.actions = actions = []
        for ob in self.payload:
            actions.append((ob.name, ob.getReqAttr(payloadmap[ob.name])))
        return Node.end(self, name)
    addData = Node.noData

payloadmap = {'import': 'file', 'execute': 'file', 'call': 'path'}

class DescriptionNode(Node):
    allowed_children = None
    def add(self, (name, attrs)):
        data = self.data.append
        if not attrs:
            data('<%s>' % name)
        else:
            data('<%s ' % name)
            for k, v in attrs.items():
                data(' %s="%s"' % (k, escape(v)))
            data('>')
    def end(self, name):
        data = self.data.append
        if name == self.name:
            return 1
        data('</%s>' % name)

class PayloadNode(Node):
    allowed_children = ('import', 'execute', 'call')
    def start(self):
        self.noAttrs()
    def add(self, node):
        self.payload.append(node)
    addData = Node.noData

class AttrNode(Node):
    addData = Node.noData

NodeMap = {
    'example': ExampleNode,
    'description': DescriptionNode,
    'payload': PayloadNode,
    'view': AttrNode,
    'import': AttrNode,
    'execute': AttrNode,
    'call': AttrNode,
    }

class XmlParser(Shared.DC.xml.xmllib.XMLParser):
    def __init__(self):
        Shared.DC.xml.xmllib.XMLParser.__init__(self)
        self.root = self.node = RootNode()
        self.tagstack = []
        
    def parse(self, data):
        self.feed(data)
        self.close()
        return self.root.out()
    
    def unknown_starttag(self, name, attrs):
        node = self.node
        if node.allowed_children is None:
            node.add((name, attrs))
        else:
            if name not in node.allowed_children:
                raise ExampleError, '%s not allowed in %s' % (name, node.name)
            newnode = NodeMap[name](name, attrs)
            node.add(newnode)
            self.tagstack.append(node)
            self.node = newnode

    def unknown_endtag(self, name):
        if self.node.end(name):
            self.node = self.tagstack.pop()

    def handle_cdata(self, data):
        self.node.addData(data, cdata=1)

    def handle_data(self, data):
        self.node.addData(data)

    def unknown_entityref(self, data):
        self.node.addData(data)

    def syntax_error(self, message):
        raise ExampleError, message


=== Packages/OFS/Application.py 1.160 => 1.160.12.1 ===
 from zLOG import LOG, ERROR, WARNING, INFO
 from HelpSys.HelpSys import HelpSys
-
-
-_standard_error_msg='''\
-<dtml-var standard_html_header>
-
-<dtml-if error_message>
- <dtml-var error_message>
-<dtml-else>
-
-  <H2>Site Error</H2>
-
-  <P>An error was encountered while publishing this resource.
-  </P>
-  
-  <P>
-  <STRONG>Error Type: <dtml-var error_type html_quote></STRONG><BR>
-  <STRONG>Error Value: <dtml-var error_value html_quote></STRONG><BR> 
-  </P>
- 
-  <HR NOSHADE>
- 
-  <P>Troubleshooting Suggestions</P>
-
-  <UL>
-  <dtml-if "error_type in ('KeyError','NameError')">
-  <LI>This resource may be trying to reference a
-  nonexistent object or variable <STRONG><dtml-var error_value></STRONG>.</LI>
-  </dtml-if>
-  <LI>The URL may be incorrect.</LI>
-  <LI>The parameters passed to this resource may be incorrect.</LI>
-  <LI>A resource that this resource relies on may be encountering
-      an error.</LI>
-  </UL>
-
-  <P>For more detailed information about the error, please
-  refer to the HTML source for this page.
-  </P>
-
-  <P>If the error persists please contact the site maintainer.
-  Thank you for your patience.
-  </P>
-
-  <dtml-comment>
-   Here, events like logging and other actions may also be performed, such as
-   sending mail automatically to the administrator.
-  </dtml-comment>
-
-</dtml-if>
-<dtml-var standard_html_footer>'''
-
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
 
 class Application(Globals.ApplicationDefaultPermissions,
                   ZDOM.Root, Folder.Folder,
@@ -171,10 +122,8 @@
     p_=misc_.p_
     misc_=misc_.misc_
 
-    _reserved_names=('standard_html_header',
-                     'standard_html_footer',
-                     'standard_error_message',
-                     'Control_Panel')
+    _reserved_names=('Control_Panel',)
+
 
     # This class-default __allow_groups__ ensures that the
     # emergency user can still access the system if the top-level
@@ -197,26 +146,6 @@
         cpl._init()
         self._setObject('Control_Panel', cpl)
 
-        # Note that this may happen before products are
-        # installed, so we have to use addDocument as stand-alone.
-        import Document
-        Document.manage_addDocument(
-            self,
-            'standard_html_header',
-            'Standard Html Header', (
-            '<html><head><title>&dtml-title_or_id;' 
-            '</title></head><body bgcolor="#FFFFFF">') )
-        Document.manage_addDocument(
-            self,
-            'standard_html_footer',
-            'Standard Html Footer',
-            '</body></html>')
-        Document.manage_addDocument(
-            self,
-            'standard_error_message',
-            'Standard Error Message',
-            _standard_error_msg)
-
     def id(self):
         try:    return self.REQUEST['SCRIPT_NAME'][1:]
         except: return self.title
@@ -363,8 +292,6 @@
             return 1
         return 0
 
-
-
 class Expired(Globals.Persistent):
     icon='p_/broken'
 
@@ -408,17 +335,6 @@
         get_transaction().note('Added Control_Panel.Products')
         get_transaction().commit()
 
-    # b/c: Ensure that std err msg exists.
-    if not hasattr(app, 'standard_error_message'):
-        import Document
-        Document.manage_addDocument(
-            app,
-            'standard_error_message',
-            'Standard Error Message',
-            _standard_error_msg)
-        get_transaction().note('Added standard_error_message')
-        get_transaction().commit()
-
     # b/c: Ensure that Owner role exists.
     if hasattr(app, '__ac_roles__') and not ('Owner' in app.__ac_roles__):
         app.__ac_roles__=app.__ac_roles__ + ('Owner',)
@@ -449,6 +365,7 @@
             get_transaction().commit()
 
     install_products(app)
+    install_standards(app)
 
     # Note that the code from here on only runs if we are not a ZEO
     # client, or if we are a ZEO client and we've specified by way
@@ -733,6 +650,28 @@
                 if raise_exc:
                     raise
 
+def install_standards(app):
+    # Install the replaceable standard objects
+    std_dir = os.path.join(Globals.package_home(globals()), 'standard')
+    for fn in os.listdir(std_dir):
+        base, ext = os.path.splitext(fn)
+        if ext == '.dtml':
+            ob = Globals.DTMLFile(base, std_dir)
+            fn = base
+            if not hasattr(app, fn):
+                app.manage_addProduct['OFSP'].manage_addDTMLMethod(
+                    id=fn, file=open(ob.raw))
+        elif ext in ('.pt', '.zpt'):
+            ob = PageTemplateFile(fn, std_dir, __name__=fn)
+            if not hasattr(app, fn):
+                app.manage_addProduct['PageTemplates'].manage_addPageTemplate(
+                    id=fn, title='', text=open(ob.filename))
+                
+        ob.__replaceable__ = Globals.REPLACEABLE
+        setattr(Application, fn, ob)
+
+    get_transaction().note('Installed standard objects')
+    get_transaction().commit()
 
 def reinstall_product(app, product_name):
     folder_permissions = get_folder_permissions()


=== Packages/OFS/Folder.py 1.96 => 1.96.12.1 ===
 from webdav.WriteLockInterface import WriteLockInterface
 from AccessControl import Unauthorized
+import Examples
 
 from Globals import DTMLFile
 from AccessControl import getSecurityManager
@@ -141,6 +142,7 @@
 
 
 class Folder(
+    Examples.Examples,
     ObjectManager.ObjectManager,
     PropertyManager.PropertyManager,
     AccessControl.Role.RoleManager,