[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()