[Zope3-checkins] CVS: Zope3/src/zope/configuration - __init__.py:1.1.2.1 action.py:1.1.2.1 exceptions.py:1.1.2.1 hookregistry.py:1.1.2.1 meta.py:1.1.2.1 meta.zcml:1.1.2.1 metaconfigure.py:1.1.2.1 metameta.zcml:1.1.2.1 metametaconfigure.py:1.1.2.1 metametaconfigurefordocgen.py:1.1.2.1 metametafordocgen.zcml:1.1.2.1 name.py:1.1.2.1 xmlconfig.py:1.1.2.1

Jim Fulton jim@zope.com
Mon, 23 Dec 2002 14:32:44 -0500


Update of /cvs-repository/Zope3/src/zope/configuration
In directory cvs.zope.org:/tmp/cvs-serv19908/zope/configuration

Added Files:
      Tag: NameGeddon-branch
	__init__.py action.py exceptions.py hookregistry.py meta.py 
	meta.zcml metaconfigure.py metameta.zcml metametaconfigure.py 
	metametaconfigurefordocgen.py metametafordocgen.zcml name.py 
	xmlconfig.py 
Log Message:
Initial renaming before debugging

=== Added File Zope3/src/zope/configuration/__init__.py ===
##############################################################################
#
# 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.
# 
##############################################################################
"""Zope configuration support

Software that wants to provide new config directives calls
Zope.Configuration.meta.register.
"""

def namespace(suffix):
    return 'http://namespaces.zope.org/'+suffix

import sys, os
from zope.configuration.xmlconfig import XMLConfig

def config(dir):
    try:
        XMLConfig(os.path.join(dir, 'site.zcml'))()
    except:
        # Use the ExceptionFormatter to provide XMLconfig debug info
        from zope.exceptions.exceptionformatter import format_exception
        exc_info = ['='*72, '\nZope Configuration Error\n', '='*72, '\n'] \
                   + apply(format_exception, sys.exc_info())
        sys.stderr.write(''.join(exc_info))
        sys.exit(0) # Fatal config error

__all__ = ["namespace", "config"]


=== Added File Zope3/src/zope/configuration/action.py ===
##############################################################################
#
# 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: action.py,v 1.1.2.1 2002/12/23 19:32:42 jim Exp $
"""

def Action(discriminator, callable, args=(), kw={}):
    return discriminator, callable, args, kw



=== Added File Zope3/src/zope/configuration/exceptions.py ===
##############################################################################
#
# Copyright (c) 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.
# 
##############################################################################
"""Standard configuration errors
"""

class ConfigurationError(Exception):
    """There was an error in a configuration
    """



=== Added File Zope3/src/zope/configuration/hookregistry.py ===
##############################################################################
#
# 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: hookregistry.py,v 1.1.2.1 2002/12/23 19:32:42 jim Exp $
"""

from types import ModuleType
from zope.exceptions import DuplicationError, NotFoundError, ZopeError
import zope.configuration.name

class MissingHookableError(NotFoundError):
    """the stated hook has not been registered"""
    
class DuplicateHookError(DuplicationError):
    """an implementation for the given hook has already been registered"""

class BadHookableError(ZopeError):
    """hookable cannot be found or is not usable"""
    
class BadHookError(ZopeError):
    """hook cannot be set"""
    
class HookRegistry:
    def __init__(self):
        self._reg = {}
    
    def addHookable(self, hname):
        if hname in self._reg:
            raise DuplicationError(hname)
        try:
            defaultimpl = name.resolve(hname)
        except ImportError:
            raise BadHookableError("hookable %s cannot be found" % hname)
        
        parent, last=self._getParentAndLast(hname)
        implfunc="%s_hook" % last
        
        if getattr(parent, implfunc, self) is self:
            raise BadHookableError(
                """default hookable implementation (%s) cannot be found;
                note it must be in the same module as the hookable""" %
                implfunc)
        
        self._reg[hname] = 0
    
    def addHook(self, hookablename, hookname):
        
        if not (hookablename in self._reg):
            raise MissingHookableError(hookablename)
        if self._reg[hookablename]:
            raise DuplicateHookError(hookablename, hookname)
        try:
            implementation = name.resolve(hookname)
        except ImportError:
            raise BadHookError('cannot find implementation', hookname)
        try:
            hookableDefault=name.resolve(hookablename)
        except:
            raise BadHookableError(
                'hookable cannot be found, but was found earlier: '
                'some code has probably masked the hookable',
                hookablename)
        
        # This won't work as is: I'd have to create a NumberTypes and do
        # various annoying checks
        #if type(implementation) is not type (hookableDefault):
        #    raise BadHookError(
        #        'hook and hookable must be same type')
        
        # if they are functions, could check to see if signature is same
        # (somewhat tricky because functions and methods could be
        # interchangable but would have a different signature because
        # of 'self')
        
        # for now I'll leave both of the above to the sanity of the site
        # configuration manager...
            
        # find and import immediate parent
        
        parent,last = self._getParentAndLast(hookablename)
        
        # set parent.last to implementation
        setattr(parent, "%s_hook" % last, implementation)
        
        self._reg[hookablename] = hookname
    
    def _getParentAndLast(self, hookablename):
        if hookablename.endswith('.') or hookablename.endswith('+'):
            hookablename = hookablename[:-1]
            repeat = 1
        else:
            repeat = 0
        names = hookablename.split(".")
        last = names.pop()
        importname = ".".join(names)
        if not importname:
            if not repeat:
                raise BadHookableError(
                    'hookable cannot be on top level of Python namespace',
                    hookablename)
            importname = last
        parent = __import__(importname, {}, {}, ('__doc__',))
        child = getattr(parent, last, self)
        if child is self:
            raise BadHookableError(
                'hookable cannot be on top level of Python namespace',
                hookablename)
        while repeat:
            grand = getattr(child, last, self)
            if grand is self:
                break
            parent = child
            child = grand
        
        if type(parent) is not ModuleType:
            raise BadHookableError("parent of hookable must be a module")
        
        return parent, last
    
    def getHooked(self):
        return [(key, self._reg[key])
                for key in self._reg
                if self._reg[key]]
    
    def getUnhooked(self):
        return [(key, self._reg[key])
                for key in self._reg
                if not self._reg[key]]
    
    def getHookables(self):
        return [(key, self._reg[key])
                for key in self._reg]


=== Added File Zope3/src/zope/configuration/meta.py ===
##############################################################################
#
# 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.
# 
##############################################################################
"""Registration of registration directives

See IEmptyDirective, INonEmptyDirective, and ISubdirectiveHandler.

$Id: meta.py,v 1.1.2.1 2002/12/23 19:32:42 jim Exp $
"""


from zope.interfaces.configuration import INonEmptyDirective
from zope.interfaces.configuration import ISubdirectiveHandler

class InvalidDirective(Exception):
    """An invalid directive was used"""

class BrokenDirective(Exception):
    """A directive is implemented incorrectly"""

class InvalidDirectiveDefinition(Exception):
    """The definition of a directive is incomplete or incorrect"""


#
# Registry data structure and manipulation functions.
#

# _directives is a registry that holds information on zcml directives
# and subdirectives.  It is filled by the 'directives', 'directive' and
# 'subdirective' directives that are provided as the bootstrap
# directives by the _clear function of this module.
#
# The top level of the registry is a dictionary keyed by two element
# tuples.  Each key tuple consists of a namespace designator (such as
# http://namespaces.zope.org/zope) and a directive name.  Thus, the
# key that accesses the 'directive' directive is::
#
#     (http://namespaces.zope.org/zope', 'directive')
#
# The value of a directive entry is a two element tuple consisting
# of a callable and a (possibly empty) subdirective registry.  The
# callable is the object to be called to process the directive and
# its parameters.  The callable must be either an IEmptyDirective (in
# which case the subdirective registry should be empty), or an
# INonEmptyDirective (in which case there should be one or more entries
# in the subdirective registry).
#
# A subdirective registry is also keyed by (ns, name) tuples.  Handler
# methods for subdirectives are looked up on the ISubdirectiveHandler
# object that is returned by the INonEmptyDirective that handles
# the directive to which the subdirective registry belongs.
# INonEmptyDirective objects are thus most often classes.
#
# The value of an entry in the subdirective registry is a tuple of
# two elements.  The first element is a subdirective registry, and
# the second is the name to be looked up to find the callable that
# will handle the processing of the subdirective.  That callable
# should implement either IEmtpyDirective or INonEmptyDirective.  The
# accompanying sub-subdirective registry should be empty or not,
# accordingly.

_directives = {}

def register(name, callable):
    """Register a top-level directive

    The name argument is a tuple with a namespace URI and an
    name string.

    The callable must be am IEmptyDirective or an INonEmptyDirective.

    INonEmptyDirective directives may have subdirectives. The
    subdirectives will be registered in a registry that is stored with
    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 = _directives.get(name,(None,{}))[1]
    _directives[name] = callable, subdirs
    return subdirs

def registersub(directives, name, handler_method=None):
    """Register a subdirective

    directives is the subdirective registry for the containing
    directive, which may be either a top-level directive or an
    intermediate sub-directive (if subdirectives are nested more than
    two deep).

    The name argument is a tuple with a namespace URI and an
    name string.

    The handler is not passed as it normally is for top-level
    directives. Rather, the handler will be looked up as an attribute
    of the ISubdirectiveHandler returned by INonEmptyDirective whose
    associated registry we have been passed.  The string to be
    looked up is set to the second element of the name tuple, unless
    the optional handler attribute is used to provide the lookup
    string explicitly.

    Subdirectives may have subdirectives. The subdirectives will be
    registered in a registry that is stored with the containing
    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 = directives.get(name,({},))[0]
    directives[name] = subdirs, handler_method
    return subdirs

#
# Parser handler methods.  These methods are called by the code that
# parses configuration data to process the directives and subdirectives.
# 'begin' is called to start processing a directive.  Its return
# value should be saved.  When the directive is closed (which will
# be right away for IEmptyDirectives), that saved return value is
# passed to end, which will return a list of actions to append to
# the action list.  Nested subdirectives are processed similarly,
# except that 'sub' is called to start them rather than begin, and
# the first argument passed to sub should be the tuple returned
# by begin (or sub) for the enclosing (sub)directive (it will be
# an ISubdirectiveHandler, subdirectiveregistry pair).  The
# end result will be a list of actions.  See IEmptyDirective for a
# description of the actions data structure.
#

def _exe(callable, subs, context, kw):
    """Helper function to turn an IxxxDirective into a (callable, subs) tuple
    """

    # We've either got an IEmptyDirective or an INonEmptyDirective here.
    # For the former, we're going to get back a list of actions when
    # we call it.  For the latter, we're going to get back an
    # ISubdirectiveHandler.  We need to return something that end
    # can call the first element of to get a list of actions.
    # ISubdirectiveHandler qualifies, but we'll have to manufacture
    # one if we got a list of actions.  When we return the
    # ISubdirectiveHandler, the parsing code calling begin/sub is
    # going to pass the tuple along to sub in order to process the
    # subdirectives.

    r = callable(context, **kw)

    if INonEmptyDirective.isImplementedBy(callable):
        return r, subs
    else:
        return (
            (lambda: r),
            subs,
            )

def begin(_custom_directives, _name, _context, **kw):
    """Begin executing a top-level directive

    A custom registry is provided to provide specialized directive
    handlers in addition to the globally registered directives. For
    example, the XML configuration mechanism uses these to provide XML
    configuration file directives.

    The _name argument is a tuple with a namespace URI and a
    name string.

    The _context argument is an execution context object that
    directives use for functions like resolving names. It will be
    passed as the first argument to the directive handler.

    kw are the directive arguments.

    The return value is a tuple that contains:

    - An object to be called to finish directive processing. This
      object will return a sequence of actions. The object must be
      called after sub-directives are processed.

    - A registry for looking up subdirectives.

    """
    
    if _custom_directives and (_name in _custom_directives):
        callable, subs = _custom_directives[_name]
    else:
        try:
            callable, subs = _directives[_name]
        except KeyError:
            raise InvalidDirective(_name)

    return _exe(callable, subs, _context, kw)

def sub(handlertuple, _name, _context, **kw):
    """Begin executing a subdirective

    The first argument, handlertuple, is a pair consisting of
    an ISubdirectiveHandler and a registry of allowable subdirectives
    for the containing directive or subdirective.

    The _name argument is a tuple with a namespace URI and a
    name string, naming the subdirective we are executing.

    The _context argument is an execution context object that
    directives use for functions like resolving names. It will be
    passed as the first argument to the directive handler.

    kw are the directive arguments.

    The return value is a tuple that contains:

    - An object to be called to finish directive processing. This
      object will return a sequence of actions. The object must be
      called after sub-directives are processed.

    - A registry for looking up sub-subdirectives.

    """

    base, subdirs = handlertuple
    try:
        subsubs, handler_method = subdirs[_name]
    except KeyError:
        raise InvalidDirective(_name)
        
    callable = getattr(base, handler_method)

    return _exe(callable, subsubs, _context, kw)

defaultkw = ({},)
def end(base):
    """Finish processing a directive or subdirective

    The argument is a return value from begin or sub.  Its first
    element is called to get a sequence of actions.

    The return value is a list of actions that are normalized to a
    4-element tuple with a descriminator, a callable, positional
    arguments, and keyword arguments.
    """

    actions = base[0]()
    ractions = []
    for action in actions:
        if len(action) < 3 or len(action) > 4:
            raise BrokenDirective(action)
        if len(action) == 3:
            action += defaultkw
        ractions.append(action)
    return ractions


#
# The code below provides the implementation for the directives,
# directive, and subdirective handlers.  These will be called
# via begin and sub when the code parsing a (meta) configuration
# file encounters these directives.  The association between
# the directive names and the particular callables is set up
# in _clear.
#

class DirectiveNamespace:

    __class_implements__ = INonEmptyDirective
    __implements__ = ISubdirectiveHandler

    def __init__(self, _context, namespace):
        self._namespace = namespace

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


class Subdirective:
    """This is the meta-meta-directive"""
    # 
    # Unlike other directives, it doesn't return any actions, but
    # takes action right away, since its actions are needed to process other
    # directives.
    # 
    # For this reason, this isn't a good directive example.

    __implements__ = ISubdirectiveHandler

    def __init__(self, subs, namespace=None):
        self._subs = subs
        self._namespace = namespace

    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

    def __call__(self):
        return ()

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.
    #
    # The data structure created here is recursive.  This allows for
    # an unlimited number of levels of subdirective definition
    # nesting.
    #
    # 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')
    subs = {}
    subs[subdirkey] = (subs, 'subdirective')
    directive = {(zopens, 'directive'): (subs, 'directive')}
    _directives[(zopens, 'directives')] = (DirectiveNamespace, directive)

_clear()

# Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
from zope.testing.cleanup import addCleanUp
addCleanUp(_clear)
del addCleanUp


=== Added File Zope3/src/zope/configuration/meta.zcml ===
<zopeConfigure xmlns='http://namespaces.zope.org/zope'>

  <!-- Zope.Configure -->
  <directives namespace="http://namespaces.zope.org/zope">
    <directive name="hookable" attributes="name module"
       handler="zope.configuration.metaconfigure.provideHookable" />
    <directive name="hook" attributes="name implementation module"
       handler="zope.configuration.metaconfigure.provideHook" />
  </directives>

</zopeConfigure>


=== Added File Zope3/src/zope/configuration/metaconfigure.py ===
##############################################################################
#
# 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: metaconfigure.py,v 1.1.2.1 2002/12/23 19:32:42 jim Exp $
"""
from zope.configuration.action import Action
from zope.configuration.hookregistry import HookRegistry

# one could make hookRegistry a service and
# theoretically use it TTW, but that doesn't immediately seem like a
# great idea
hookRegistry = HookRegistry()

addHookable = hookRegistry.addHookable
addHook = hookRegistry.addHook

def provideHookable(_context, name, module=None):
    if module:
        name = "%s.%s" % (module, name)
    name = _context.getNormalizedName(name)
    return [
        Action(
            discriminator=('addHookable', name),
            callable=addHookable,
            args=(name,)
            )
        ]


def provideHook(_context, name, implementation, module=None):
    if module:
        name = "%s.%s" % (module, name)
    name = _context.getNormalizedName(name)
    implementation = _context.getNormalizedName(implementation)
    return [
        Action(
            discriminator=('addHook', name),
            callable=addHook,
            args=(name, implementation)
            )
        ]





=== Added File Zope3/src/zope/configuration/metameta.zcml ===
<zopeConfigure xmlns='http://namespaces.zope.org/zope'>

<directives namespace="http://namespaces.zope.org/zope">

  <!-- Modify the bootstrap meta configuration directives

  Note that we are modifying the handler we are using to
  process the text that is triggering the modifications.
  However, since modifications are non-destructive of
  any pre-existing subdirective structure, this works.
  Further, since the bootstrap namespace for subdirective
  is recursive, we only have to modify subdirective once.

  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="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
          name="subdirective"
          attributes="name attributes namespace handler_method description"
      >
        <subdirective
            name="attribute"
            attributes="name description required" />
      </subdirective>
    </subdirective>
  </directive>
     
</directives>

</zopeConfigure>


=== Added File Zope3/src/zope/configuration/metametaconfigure.py ===
##############################################################################
#
# 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: metametaconfigure.py,v 1.1.2.1 2002/12/23 19:32:42 jim Exp $
"""
from zope.configuration.meta import DirectiveNamespace as bootstrapDirectiveNamespace
from zope.configuration.meta import Subdirective as bootstrapSubdirective
from zope.interfaces.configuration import INonEmptyDirective
from zope.interfaces.configuration import IEmptyDirective
from zope.interfaces.configuration 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


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


=== Added File Zope3/src/zope/configuration/metametaconfigurefordocgen.py ===
##############################################################################
#
# 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: metametaconfigurefordocgen.py,v 1.1.2.1 2002/12/23 19:32:42 jim Exp $
"""
from zope.configuration.metametaconfigure import DirectiveNamespace as baseDirectiveNamespace
from zope.configuration.metametaconfigure import Subdirective as baseSubdirective
from zope.interfaces.configuration import INonEmptyDirective
from zope.interfaces.configuration 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)


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}


=== Added File Zope3/src/zope/configuration/metametafordocgen.zcml ===
<zopeConfigure xmlns='http://namespaces.zope.org/zope'>

<directives namespace="http://namespaces.zope.org/zope">
  <!-- Install the docgen version of the meta configuration handler -->
  <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="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>
      <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." />
        <!--
             We don't need to redefine the attribute subdirective of
             the subdirective subdirective, because defining it in
             directive's namespace defined it in the same (recursive)
             namespace subdirective uses.
        -->
      </subdirective>
    </subdirective>
  </directive>

</directives>

</zopeConfigure>


=== Added File Zope3/src/zope/configuration/name.py ===
##############################################################################
#
# 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.
# 
##############################################################################
"""Provide configuration object name resolution

$Id: name.py,v 1.1.2.1 2002/12/23 19:32:42 jim Exp $
"""

import os
import sys
from types import ModuleType

def resolve(name, package='ZopeProducts', _silly=('__doc__',), _globals={}):
    name = name.strip()
    
    if name.startswith('.'):
        name=package+name

    if name.endswith('.') or name.endswith('+'):
        name = name[:-1]
        repeat = 1
    else:
        repeat = 0

    names=name.split('.')
    last=names[-1]
    mod='.'.join(names[:-1])

    if not mod:
        return __import__(name, _globals, _globals, _silly)
                 
    while 1:
        m=__import__(mod, _globals, _globals, _silly)
        try:
            a=getattr(m, last)
        except AttributeError:
            if not repeat:
                return __import__(name, _globals, _globals, _silly)
                
        else:
            if not repeat or (not isinstance(a, ModuleType)):
                return a
        mod += '.' + last


def getNormalizedName(name, package):
    name=name.strip()
    if name.startswith('.'):
        name=package+name

    if name.endswith('.') or name.endswith('+'):
        name = name[:-1]
        repeat = 1
    else:
        repeat = 0
    name=name.split(".")
    while len(name)>1 and name[-1]==name[-2]:
        name.pop()
        repeat=1
    name=".".join(name)
    if repeat:
        name+="+"
    return name

def path(file='', package = 'ZopeProducts', _silly=('__doc__',), _globals={}):
    try: package = __import__(package, _globals, _globals, _silly)
    except ImportError:
        if file and os.path.abspath(file) == file:
            # The package didn't matter
            return file
        raise
        
    path = os.path.split(package.__file__)[0]
    if file:
        path = os.path.join(path, file)
    return path


=== Added File Zope3/src/zope/configuration/xmlconfig.py ===
##############################################################################
#
# 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: xmlconfig.py,v 1.1.2.1 2002/12/23 19:32:42 jim Exp $
"""

import os
import zope.configuration.name
from os.path import abspath
from xml.sax import make_parser
from xml.sax.xmlreader import InputSource
from xml.sax.handler import ContentHandler, feature_namespaces
from zope.configuration.meta import begin, sub, end
from keyword import iskeyword
import sys, os
from types import StringType
from zope.configuration.exceptions import ConfigurationError

# marker used in Context class and XMLConfig class to indicate
# that a particular zcml file was given no "package" attribute 
# when included, and the same went for all of its parents.
_NO_MODULE_GIVEN = object()

class ZopeXMLConfigurationError(ConfigurationError):
    "Zope XML Configuration error"

    def __init__(self, locator, mess, etype=None):
        if etype is None:
            if not isinstance(mess, StringType):
                try:
                    mess = "\n%s:\n  %s" % (mess.__class__.__name__, mess)
                except AttributeError:
                    mess = str(mess)
        else:
            mess = "\n%s: %s" % (etype.__name__, mess)
            
        self.lno = locator.getLineNumber()
        self.cno = locator.getColumnNumber()
        self.sid = locator.getSystemId()
        self.mess = mess

    def __str__(self):
        return 'File "%s", line %s, column %s\n\t%s' % (
            self.sid, self.lno, self.cno, self.mess)

class ConfigurationExecutionError(ZopeXMLConfigurationError):
    """An error occurred during execution of a configuration action
    """

    def __init__(self, locator, mess, etype=None):
        if etype is None:
            if isinstance(mess, StringType):
                try:
                    mess = "%s: %s" % (mess.__class__.__name__, mess)
                except AttributeError:
                    mess = str(mess)
        else:
            mess = "\n%s: %s" % (etype.__name__, mess)

        self.lno, self.cno, self.sid = locator
        self.mess = mess

class ConfigurationHandler(ContentHandler):

    __top_name = 'http://namespaces.zope.org/zope', 'zopeConfigure' 

    def __init__(self, actions, context, directives=None, testing=0):
        self.__stack = []
        self.__actions = actions
        self.__directives = directives
        self.__context = context
        self.__testing = testing

    def setDocumentLocator(self, locator):
        self.__locator = locator

    def startElementNS(self, name, qname, attrs):
        stack = self.__stack
        if not stack:
            if name != self.__top_name:
                raise ZopeXMLConfigurationError(
                    self.__locator, "Invalid top element: %s %s" % name)

            for (ns, aname), value in attrs.items():
                if ns is None:
                    self.__context.file_attr(aname, value)
                    

            stack.append(None)
            return

        kw = {}
        for (ns, aname), value in attrs.items():
            if ns is None:
                aname = str(aname)
                if iskeyword(aname): aname += '_'
                kw[aname] = value

        if len(stack) == 1:
            try:
                stack.append(
                    begin(self.__directives, name, self.__context, **kw)
                    )
            except Exception, v:
                if self.__testing:
                    raise
                raise ZopeXMLConfigurationError, (
                    self.__locator, v), sys.exc_info()[2] 
                
        else:
            subs = self.__stack[-1]
            if subs is None:
                raise ZopeXMLConfigurationError(self.__locator,
                                                'Invalid sub-directive')
            try:
                stack.append(sub(subs, name, self.__context, **kw))
            except Exception, v:
                if self.__testing:
                    raise
                raise ZopeXMLConfigurationError, (
                    self.__locator, v), sys.exc_info()[2] 

    def endElementNS(self, name, qname):
        subs = self.__stack.pop()
        # to fool compiler that thinks actions is used before assignment:
        actions = ()

        if subs is not None:
            try:
                actions = end(subs)
            except Exception, v:
                if self.__testing:
                    raise
                raise ZopeXMLConfigurationError, (
                    self.__locator, str(v)), sys.exc_info()[2] 

        append = self.__actions.append

        try:
            for des, callable, args, kw in actions:
                append((self.__context,
                        (self.__locator.getLineNumber(),
                         self.__locator.getColumnNumber(),
                         self.__locator.getSystemId(),
                         ), des, callable, args, kw))
        except:
            print 'endElementNS', actions
            raise

class ZopeConflictingConfigurationError(ZopeXMLConfigurationError):
    "Zope XML Configuration error"

    def __init__(self, l1, l2, des):
        self.l1 = l1
        self.l2 = l2
        self.des = des

    def __str__(self):
        return """Conflicting configuration action:
        %s
        File "%s", line %s column %s
        File "%s", line %s column %s
        """ % (self.des,
               self.l1[2], self.l1[0], self.l1[1], 
               self.l2[2], self.l2[0], self.l2[1],
               )
        
class Context:
    def __init__(self, stack, module):
        self.__stackcopy = tuple(stack)
        if module is _NO_MODULE_GIVEN:
            self.__package = None
        elif module is None:
            self.__package = 'ZopeProducts'
        else:
            self.__package = module.__name__

    def _stackcopy(self):
        return self.__stackcopy

    def resolve(self, dottedname):
        return name.resolve(dottedname, self.__package)
    
    def getNormalizedName(self, dottedname):
        return name.getNormalizedName(dottedname, self.__package)

    def path(self, file=None):
        return name.path(file, self.__package)

    def file_attr(self, name, value):
        if name == 'package':
            self.__package = value
        else:
            raise TypeError, "Unrecognized config file attribute: %s" % name

    def packageWasSet(self):
        return self.__package is not None
        
    def package(self):
        return self.__package
        
def xmlconfig(file, actions=None, context=None, directives=None,
              testing=0):
    if context is None:
        context = name

    if actions is None:
        call = actions = []
    else:
        call = 0
    
    src = InputSource(getattr(file, 'name', '<string>'))
    src.setByteStream(file)
    parser = make_parser()
    parser.setContentHandler(
        ConfigurationHandler(actions, context,directives,
                             testing=testing)
        )
    parser.setFeature(feature_namespaces, 1)
    parser.parse(src)

    if call:
        descriptors = {}
        for level, loc, des, callable, args, kw in call:
            if des is not None:
                if des in descriptors:
                    raise ZopeConflictingConfigurationError(
                        descriptors[des], loc, des)
                descriptors[des] = loc
                
            callable(*args, **kw)

def testxmlconfig(file, actions=None, context=None, directives=None):
    """xmlconfig that doesn't raise configuration errors

    This is useful for testing, as it doesn't mask exception types.
    """
    return xmlconfig(file, actions, context, directives, testing=1)
            
class ZopeConfigurationConflictError(ZopeXMLConfigurationError):

    def __init__(self, conflicts):
        self._conflicts = conflicts

    def __str__(self):
        r = ["Conflicting configuration actions"]
        for dis, locs in self._conflicts.items():
            r.append('for: %s' % (dis,))
            for loc in locs:
                r.append('  File "%s", line %s column %s' %
                         (loc[2], loc[0], loc[1]))
        
        return "\n".join(r)
        

class XMLConfig:

    def __init__(self, file_name, module=_NO_MODULE_GIVEN):
        if module is not None and module is not _NO_MODULE_GIVEN:
            module_dir = abspath(os.path.split(module.__file__)[0])
            file_name = os.path.join(module_dir, file_name)

        
        self._actions = []
        self._directives = {('http://namespaces.zope.org/zope', 'include'):
                            (self.include, {})}

        f = open(file_name)
        self._stack = [file_name]
        xmlconfig(f, self._actions,
                  Context(self._stack, module=module),
                  self._directives)
        f.close()

    def include(self, _context, file='configure.zcml', package=None):
        if package is None and _context.packageWasSet():
            package = _context.package()
        subpackages = False
        if package is not None:
            if package.endswith('.*'):
                # <include package="package.*" /> includes all subpackages
                subpackages = True
                parent = package = package[:-2]
                if package == "":
                    package = "."
            try:
                package = _context.resolve(package)
                if len(package.__path__) != 1:
                    print ("Module Path: '%s' has wrong number of elements"
                            % str(package.__path__))
                # XXX: This should work for 99% of cases
                # We may want to revisit this with a more robust
                # mechanism later. Specifically, sometimes __path__
                # will have more than one element. Also, we could
                # use package.__file__, and lop the tail off that.
                prefix = package.__path__[0]
            except (ImportError, AttributeError, ValueError), v:
                raise # XXX the raise below hides the real error
                raise ValueError("Invalid package attribute: %s\n(%s)"
                                 % (package, `v`))
        else:
            prefix = os.path.dirname(self._stack[-1])

        if subpackages:
            for subdir in os.listdir(prefix):
                file_name = os.path.join(prefix, subdir, file)
                if not os.access(file_name, os.F_OK):
                    continue
                subpackage = "%s.%s" % (parent, subdir)
                subpackage = _context.resolve(subpackage)
                self._include(file_name, subpackage)
        else:
            file_name = os.path.join(prefix, file)
            self._include(file_name, package)
        return ()

    def _include(self, file_name, package):

        f = open(file_name)
        self._stack.append(file_name)
        xmlconfig(f, self._actions, Context(self._stack, package),
                  self._directives)
        self._stack.pop()
        f.close()

    def __call__(self):
        self.organize()

    def __iter__(self): return iter(self._actions)

    def organize(self):
        actions = self._actions

        # organize actions by discriminators
        unique = {}
        cactions = []
        for i in range(len(actions)):
            context, loc, des, callable, args, kw = actions[i]
            if des is None:
                # The descriminator is None, so this directive can
                # never conflict. We can add it directly to the
                # configuration actions.
                cactions.append((i, loc, (callable, args, kw)))
                continue

            a = unique.setdefault(des, [])
            a.append((context._stackcopy(), i, loc, (callable, args, kw)))

        # Check for conflicts
        conflicts = {}
        for des, actions in unique.items():
            path, i, loc, f = actions[0]
            for opath, i, oloc, f in actions[1:]:
                # Test whether path is a prefix of opath
                if opath[:len(path)] != path or (opath == path):
                    if des not in conflicts:
                        conflicts[des] = [loc]
                    conflicts[des].append(oloc)

        if conflicts:
            raise ZopeConfigurationConflictError(conflicts)

        # Now order the configuration directives
        for des, actions in unique.items():
            path, i, loc, f = actions.pop(0)
            cactions.append((i, loc, f))

        unique = None

        cactions.sort()

        # Call actions
        for i, loc, f in cactions:
            try:
                callable, args, kw = f
                callable(*args, **kw)
            except Exception, v:
                raise ConfigurationExecutionError, (
                    loc, v, sys.exc_info()[0]), sys.exc_info()[2]