[Zope3-checkins] CVS: Zope3/lib/python/Zope/Configuration - metameta.zcml:1.2 metametaConfigure.py:1.2 metametaConfigureForDocgen.py:1.2 metametaForDocgen.zcml:1.2 meta.py:1.16

R. David Murray bitz@bitdance.com
Wed, 6 Nov 2002 17:30:53 -0500


Update of /cvs-repository/Zope3/lib/python/Zope/Configuration
In directory cvs.zope.org:/tmp/cvs-serv10913/lib/python/Zope/Configuration

Modified Files:
	meta.py 
Added Files:
	metameta.zcml metametaConfigure.py 
	metametaConfigureForDocgen.py metametaForDocgen.zcml 
Log Message:
Merge of rdmurray-metameta-branch.  See checkin message for 
doc/zcml/meta.stx for a more comprehensive checkin comment.


=== Zope3/lib/python/Zope/Configuration/metameta.zcml 1.1 => 1.2 ===
--- /dev/null	Wed Nov  6 17:30:53 2002
+++ Zope3/lib/python/Zope/Configuration/metameta.zcml	Wed Nov  6 17:30:22 2002
@@ -0,0 +1,78 @@
+<zopeConfigure xmlns='http://namespaces.zope.org/zope'>
+
+<directives namespace="http://namespaces.zope.org/zope">
+
+  <!-- Modify the bootstrap meta configuration directives
+
+  Note that the order we do this is important because we are
+  modifying the handlers we are using to process the text
+  that is triggering the modifications.
+
+  The first section here modifies the "directive" top-level
+  directive, which we aren't using in this file.  The second
+  section modifies the "directives" directive, which is the
+  directive used to trigger the modification.  So the handler
+  doesn't get changed until after it has already been called, and
+  all is well.
+
+  This file is perhaps a little bit too magical, since it depends
+  on the bootstrap registry's recursive data structure for
+  'subdirective' (the thing that allows subdirectives to be
+  defined to any desired nesting level).  But it's really pretty
+  straightforward:  we only need to modify the definition of
+  subdirective once, and that changes it both places it gets
+  used (directives/directive/subdirective and directive/subdirective)
+  and of course all the possible nested calls as well.
+
+  The handler routines called out by the declarations in this
+  file simply ignore the additional information provided by the
+  modified directives, which at the moment is what we want
+  done during normal running of zope.
+
+  XXX: In the current implementation of the bootstrap code, the
+  'attributes' attribute doesn't actually do anything.  I include
+  it anyway in case the bootstrap code gets modified to actually
+  do something with attributes.  This however seems unlikely,
+  since it would make more sense to modify the attribute subdirective
+  we are introducing here.  So after people are comfortable with
+  this meta-meta configuration, we could simplify the bootstrap
+  by doing away with 'attributes' in the bootstrap code and here.
+  -->
+
+  <directive
+      name="directive"
+      attributes="namespace name handler attributes description"
+      handler="Zope.Configuration.metametaConfigure.Directive"
+  >
+    <subdirective
+        name="attribute"
+        attributes="name description required" />
+    <subdirective
+        name="subdirective"
+        attributes="name attributes namespace handler_method description"
+    >
+      <subdirective
+          name="attribute"
+          attributes="name description required" />
+    </subdirective>
+  </directive>
+
+  <directive
+      name="directives"
+      attributes="namespace name handler attributes description"
+      handler="Zope.Configuration.metametaConfigure.DirectiveNamespace"
+    >
+    <subdirective
+        name="directive"
+        attributes="namespace name handler attributes description"
+    >
+      <subdirective
+          name="attribute"
+          attributes="name description required" />
+      <!-- subdirective was already modified above -->
+    </subdirective>
+  </directive>
+     
+</directives>
+
+</zopeConfigure>


=== Zope3/lib/python/Zope/Configuration/metametaConfigure.py 1.1 => 1.2 ===
--- /dev/null	Wed Nov  6 17:30:53 2002
+++ Zope3/lib/python/Zope/Configuration/metametaConfigure.py	Wed Nov  6 17:30:22 2002
@@ -0,0 +1,80 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+# 
+##############################################################################
+"""
+$Id$
+"""
+from meta import DirectiveNamespace as bootstrapDirectiveNamespace
+from meta import Subdirective as bootstrapSubdirective
+from meta import _registerDirective
+from INonEmptyDirective import INonEmptyDirective
+from IEmptyDirective import IEmptyDirective
+from ISubdirectiveHandler import ISubdirectiveHandler
+
+#
+# Meta-meta configuration.  These routines replace the bootstrap ones
+# defined in meta.py.
+#
+
+class DirectiveNamespace(bootstrapDirectiveNamespace):
+
+    __class_implements_ = INonEmptyDirective
+    __implements__ = ISubdirectiveHandler
+
+    def _Subdirective(self, *args, **kw): return Subdirective(*args, **kw)
+
+    def _useDescription(self, namespace, name, handler, description, subs): pass
+
+    def directive(self, _context, name, handler, attributes='',
+            namespace=None, description=''):
+        subs, namespace = self._register(_context, name, handler, namespace)
+        self._useDescription(namespace, name, handler, description, subs)
+        return self._Subdirective(subs, namespace=namespace, name=name)
+    directive.__implements__ = INonEmptyDirective
+
+
+def Directive(_cotnext, namespace, name, handler, description='',
+        attributes=''):
+    subs, namespace = _registerDirective(_context, namespace, name, handler)
+    return self._Subdirective(subs, namespace=namespace, name=name)
+
+Directive.__implements__ = INonEmptyDirective
+
+
+class Subdirective(bootstrapSubdirective):
+    """An extended Subdirective that handles descriptions and attributes"""
+
+    __implements__ = ISubdirectiveHandler
+
+    def __init__(self, subs, namespace=None, name=None):
+        bootstrapSubdirective.__init__(self,subs,namespace)
+        self._name = name
+
+    def _useDescription(self, namespace, name, subs, description): pass
+
+    def subdirective(self, _context, name, attributes='',
+                     namespace=None, handler_method=None, description=''):
+        subs, namespace = self._register(_context, name, namespace,
+                                         handler_method)
+        self._useDescription(namespace, name, subs, description)
+        return self.__class__(subs, namespace=namespace, name=name)
+    subdirective.__implements__ = INonEmptyDirective
+
+    def _useAttributeDescription(self, name, required, description): pass
+
+    def attribute(self, _context, name, required='', description=''):
+        required = required.lower()
+        if required not in ('', 'yes', 'no'): raise ValueError(required)
+        self._useAttributeDescription(name, required, description)
+        return ()
+    attribute.__implements__ = IEmptyDirective


=== Zope3/lib/python/Zope/Configuration/metametaConfigureForDocgen.py 1.1 => 1.2 ===
--- /dev/null	Wed Nov  6 17:30:53 2002
+++ Zope3/lib/python/Zope/Configuration/metametaConfigureForDocgen.py	Wed Nov  6 17:30:22 2002
@@ -0,0 +1,103 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+# 
+##############################################################################
+"""
+$Id$
+"""
+from metametaConfigure import DirectiveNamespace as baseDirectiveNamespace
+from metametaConfigure import Subdirective as baseSubdirective
+from metametaConfigure import Directive as baseDirective
+from INonEmptyDirective import INonEmptyDirective
+from ISubdirectiveHandler import ISubdirectiveHandler
+
+#
+# Versions of the meta configuration directive handlers that save the
+# documentation information as structured data.
+#
+
+"""
+To track the meta-data about configuration directives, we use a
+special key that will never appear as an actual subdirective name.
+So the information stored under that key in a (sub)directive's
+subdirective registry is the meta data about the (sub)directive
+itself.
+
+That data consists of a dictionary with the following keys:
+
+description -- a description of the (sub)directive.  It should
+    explain the semantics of the (sub)directive.
+
+attributes -- a dictionary containing entries for each attribute
+    the (sub)command accepts.  The value of the entries in this
+    dictionary are dictionaries with the following keys:
+
+    description -- a description of the attribute.  It should
+        explain the semantics of the attribute.
+
+    required -- 'yes', 'no', or ''.  Applies to attributes
+        and means what it sounds like it means.  Blank is
+        more or less equivalent to except that an attribute
+        with a blank required might be one that is a member of a
+        set *one* of which is required, while if an explicit
+        'no' is given then the attribute is completely optional.
+        This information will be included in the generated doc strings.
+
+This metadata is intended to serve as the most basic level of documentation
+of the directives, and should be updated along with the directive code
+(which is why it is stored in the meta.zcml file).  The metadata should
+be extracted and made human accessible by a zope-independent program
+and/or a zope-based introspection tool.
+"""
+_metadataKey = "__Zope.Configuration.metadataKey__"
+
+def _recordCommandMetadata(subs, description, handler=None):
+        if _metadataKey not in subs: subs[_metadataKey] = {}
+        md = subs[_metadataKey]
+        if 'attributes' not in md: md['attributes'] = {}
+        if description: md['description'] = ' '.join(description.split())
+        if handler: md['handler'] = handler
+
+
+class DirectiveNamespace(baseDirectiveNamespace):
+    """An extended class that handles descriptions and attributes"""
+
+    __class_implements_ = INonEmptyDirective
+    __implements__ = ISubdirectiveHandler
+
+    def _Subdirective(self, *args, **kw): return Subdirective(*args, **kw)
+
+    def _useDescription(self, namespace, name, handler, description, subs):
+        _recordCommandMetadata(subs, description, handler)
+
+
+def Directive(_cotnext, namespace, name, handler, attributes='',
+        description=''):
+    subs = baseDirective(_context, namespace, name, handler, description)
+    _recordCommandMetadata(subs, description, handler)
+
+Directive.__implements__ = INonEmptyDirective
+
+
+class Subdirective(baseSubdirective):
+    """An extended class that handles descriptions and attributes"""
+
+    __implements__ = ISubdirectiveHandler
+
+    def _useDescription(self, namespace, name, subs, description):
+        _recordCommandMetadata(subs, description)
+
+    def _useAttributeDescription(self, name, required, description):
+        attribs = self._subs[_metadataKey]['attributes']
+        attribs[name] = {
+            'description': description and ' '.join(description.split()),
+            'required': required}


=== Zope3/lib/python/Zope/Configuration/metametaForDocgen.zcml 1.1 => 1.2 ===
--- /dev/null	Wed Nov  6 17:30:53 2002
+++ Zope3/lib/python/Zope/Configuration/metametaForDocgen.zcml	Wed Nov  6 17:30:22 2002
@@ -0,0 +1,177 @@
+<zopeConfigure xmlns='http://namespaces.zope.org/zope'>
+
+<directives namespace="http://namespaces.zope.org/zope">
+  <!-- Install the docgen versions of the meta configuration handlers -->
+  <directive
+      name="directive"
+      handler="Zope.Configuration.metametaConfigureForDocgen.Directive" />
+  <directive
+      name="directives"
+      handler="Zope.Configuration.metametaConfigureForDocgen.DirectiveNamespace" />
+</directives>
+
+<directives namespace="http://namespaces.zope.org/zope">
+
+  <!-- Add help text for the meta configuration directives -->
+
+  <directive
+      name="directive"
+      handler="Zope.Configuration.metametaConfigureForDocgen.Directive"
+      description="Define a new configuration directive."
+  >
+    <attribute
+        name="namespace"
+        required="yes"
+        description="XML-style namespace identifier for the namespace
+            in which the directive being defined will reside." />
+    <attribute
+        name="name"
+        required="yes"
+        description="the name of the directive." />
+    <attribute
+        name="handler"
+        required="yes"
+        description="resolvable name of an IEmptyDirective or an
+            INonEmptyDirective that is to be called to handle
+            the directive." />
+    <attribute
+        name="description"
+        description="structured Text sentences that document the
+            purpose and function of the directive." />
+    <subdirective
+        name="attribute"
+        description="Define an attribute that may be specified on the
+            directive being defined"
+    >
+      <attribute
+          name="name"
+          required="yes"
+          description="the name of the attribute." />
+      <attribute
+          name="required"
+          required="no"
+          description="'yes', 'no', or missing.  'yes' indicates the attribute
+              being defined *must* be specified when the directive is used.
+              'no' means it can always be omitted.  If not specified, the
+              attribute may be part of a set of attributes one of which may
+              be required." />
+      <attribute
+          name="description"
+          description="structured Text sentences describing the purpose,
+            function, and allowed values of the attribute." />
+    </subdirective>
+    <subdirective
+        name="subdirective"
+        description="Define a subdirective that may be used inside
+            the enclosing directive in a configuration."
+    >
+      <attribute
+          name="name"
+          required="yes"
+          description="the name of the subdirective" />
+      <attribute
+          name="handler_method"
+          description="the name of an IEmptyDirective or an
+              INonEmptyDirective.  The name will be looked up on the
+              ISubDirectiveHandler returned by the handler for
+              the enclosing directive.  If not specified, the
+              subdirective name is used." />
+      <attribute
+          name="description"
+          description="structured Text sentences that document the
+              purpose and function of the subdirective." />
+      <attribute
+          name="namespace"
+          description="XML-style namespace identifier for the namespace
+              in which the directives being defined will reside.  If
+              specified it overrides the namespace inherited from
+              the enclosing directive." />
+      <subdirective
+          name="attribute"
+          description="Define an attribute that may be specified on the
+              subdirective being defined"
+      >
+        <attribute
+            name="name"
+            required="yes"
+            description="the name of the attribute." />
+        <attribute
+            name="required"
+            required="no"
+            description="'yes', 'no', or missing.  'yes' indicates the attribute
+                being defined *must* be specified when the directive is used.
+                'no' means it can always be omitted.  If not specified, the
+                attribute may be part of a set of attributes one of which may
+                be required." />
+        <attribute
+            name="description"
+            description="structured Text sentences describing the purpose,
+                function, and allowed values of the attribute." />
+      </subdirective>
+    </subdirective>
+  </directive>
+
+  <directive
+      name="directives"
+      handler="Zope.Configuration.metametaConfigureForDocgen.DirectiveNamespace"
+      description="Define a set of new configuration directives within a
+          defaultnamespace"
+  >
+    <attribute
+        name="namespace"
+        required="yes"
+        description="XML-style namespace identifier for the namespace
+            in which the directives being defined will reside." />
+    <subdirective
+        name="directive"
+        description="Define a new configuration directive."
+    >
+      <attribute
+          name="name"
+          required="yes"
+          description="the name of the directive." />
+      <attribute
+          name="handler"
+          required="yes"
+          description="resolvable name of an IEmptyDirective or an
+              INonEmptyDirective that is to be called to handle
+              the directive." />
+      <attribute
+          name="namespace"
+          description="XML-style namespace identifier for the namespace
+              in which the directive being defined will reside.  If
+              specified it overrides the namespace inherited from
+              the enclosing directives directive." />
+      <attribute
+          name="description"
+          description="structured Text sentences that document the
+              purpose and function of the directive." />
+      <subdirective
+          name="attribute"
+          description="Define an attribute that may be specified on the
+              directive being defined"
+      >
+        <attribute
+            name="name"
+            required="yes"
+            description="the name of the attribute." />
+        <attribute
+            name="required"
+            required="no"
+            description="'yes', 'no', or missing.  'yes' indicates the attribute
+                being defined *must* be specified when the directive is used.
+                'no' means it can always be omitted.  If not specified, the
+                attribute may be part of a set of attributes one of which may
+                be required." />
+        <attribute
+            name="description"
+            description="structured Text sentences describing the purpose,
+              function, and allowed values of the attribute." />
+      </subdirective>
+      <!-- The descriptions for subdirective were already added above -->
+    </subdirective>
+  </directive>
+
+</directives>
+
+</zopeConfigure>


=== Zope3/lib/python/Zope/Configuration/meta.py 1.15 => 1.16 ===
--- Zope3/lib/python/Zope/Configuration/meta.py:1.15	Thu Oct  3 15:44:26 2002
+++ Zope3/lib/python/Zope/Configuration/meta.py	Wed Nov  6 17:30:22 2002
@@ -85,9 +85,12 @@
     the directive. The sub-directive registry is returned so that
     it can be used for subsequent sub-directive registration.
 
+    If the same name is registered a second time, the existing
+    subdirective registry will be returned.
+
     """
     
-    subdirs = {}
+    subdirs = _directives.get(name,(None,{}))[1]
     _directives[name] = callable, subdirs
     return subdirs
 
@@ -115,10 +118,13 @@
     subdirective. The sub-directive registry is returned so that it
     can be used for subsequent sub-directive registration.
 
+    If the same name is registered a second time, the existing
+    subdirective registry will be returned.
+
     """
     if not handler_method:
         handler_method = name[1]
-    subdirs = {}
+    subdirs = directives.get(name,({},))[0]
     directives[name] = subdirs, handler_method
     return subdirs
 
@@ -155,7 +161,7 @@
 
     r = callable(context, **kw)
 
-    if subs or INonEmptyDirective.isImplementedBy(callable):
+    if INonEmptyDirective.isImplementedBy(callable):
         return r, subs
     else:
         return (
@@ -276,22 +282,32 @@
     def __init__(self, _context, namespace):
         self._namespace = namespace
 
-    def directive(self, _context, name, handler, attributes='',
-                  namespace=None):
+    def _register(self, _context, name, handler, namespace=None,
+                  attributes=''):
         namespace = namespace or self._namespace
         subs = register((namespace, name), _context.resolve(handler))
+        return subs, namespace
+        
+    def directive(self, *args, **kw):
+        subs, namespace = self._register(*args, **kw)
         return Subdirective(subs, namespace=namespace)
     directive.__implements__ = INonEmptyDirective
 
     def __call__(self):
         return ()
 
-def Directive(_context, namespace, name, handler, attributes=''):
+
+def _registerDirective(_context, namespace, name, handler, attributes=''):
     subs = register((namespace, name), _context.resolve(handler))
+    return subs, namespace
+
+def Directive(*args, **kw):
+    subs, namespace = _registerDirective(*args, **kw)
     return Subdirective(subs, namespace=namespace)
 
 Directive.__implements__ = INonEmptyDirective
 
+
 class Subdirective:
     """This is the meta-meta-directive"""
     # 
@@ -307,13 +323,17 @@
         self._subs = subs
         self._namespace = namespace
 
-    def subdirective(self, _context, name, attributes='',
-                     namespace=None, handler_method=None):
+    def _register(self, _context, name, namespace=None, handler_method=None,
+                  attributes=''):
         namespace = namespace or self._namespace
         if not namespace:
             raise InvalidDirectiveDefinition(name)
         #If handler_method is None, registersub will use name.
         subs = registersub(self._subs, (namespace, name), handler_method)
+        return subs, namespace
+
+    def subdirective(self, *args, **kw):
+        subs, namespace = self._register(*args, **kw)
         return Subdirective(subs,namespace=namespace)
     subdirective.__implements__ = INonEmptyDirective
 
@@ -323,24 +343,30 @@
 def _clear():
     """Initialize _directives data structure with bootstrap directives."""
 
-    #We initialize _directives with handlers for three (sub)directives:
-    #directives, directive, and subdirective.  Given these three
-    #(whose implementation is contained in this module) we can use
-    #zcml to define any other directives needed for a given system.
+    # We initialize _directives with handlers for three (sub)directives:
+    # directives, directive, and subdirective.  Given these three
+    # (whose implementation is contained in this module) we can use
+    # zcml to define any other directives needed for a given system.
+    #
+    # The data structure created here is both recursive and incestuous.
+    # The recursive part allows for an unlimited number of levels
+    # of subdirective definition nesting.  The incestuous part is
+    # perhaps less legitimate, but seems logical since I can't think of
+    # a reason you would want the subdirective subdirective of the
+    # directive directive to do anything different from the subdirective
+    # subdirective of the directive subdirective of the directives
+    # directive.
     #
-    #This initialziation is done in a function to facilitate support
-    #the unittest CleanUp class.
+    # This initialziation is done in a function to facilitate support
+    # the unittest CleanUp class.
 
+    _directives.clear()
     zopens = 'http://namespaces.zope.org/zope'
     subdirkey = (zopens, 'subdirective')
-    subdir1 = {subdirkey: ({}, 'subdirective')}
-    subdir2 = {subdirkey: (subdir1, 'subdirective')}
-    subdir3 = {subdirkey: (subdir2, 'subdirective')}
-    _directives.clear()
-    _directives[(zopens, 'directive')] = (Directive, subdir3)
-    #This is incecstuous, but since there's no way to modify a
-    #directive or subdirective other than replacement, it should be OK.
-    directive = {(zopens, 'directive'): (subdir3, 'directive')}
+    subs = {}
+    subs[subdirkey] = (subs, 'subdirective')
+    _directives[(zopens, 'directive')] = (Directive, subs)
+    directive = {(zopens, 'directive'): (subs, 'directive')}
     _directives[(zopens, 'directives')] = (DirectiveNamespace, directive)
 
 _clear()