[Zope3-checkins] CVS: Zope3/src/zope/configuration - __init__.py:1.2 action.py:1.2 exceptions.py:1.2 hookregistry.py:1.2 meta.py:1.2 meta.zcml:1.2 metaconfigure.py:1.2 metameta.zcml:1.2 metametaconfigure.py:1.2 metametaconfigurefordocgen.py:1.2 metametafordocgen.zcml:1.2 name.py:1.2 xmlconfig.py:1.2
Jim Fulton
jim@zope.com
Wed, 25 Dec 2002 09:14:06 -0500
Update of /cvs-repository/Zope3/src/zope/configuration
In directory cvs.zope.org:/tmp/cvs-serv15352/src/zope/configuration
Added Files:
__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:
Grand renaming:
- Renamed most files (especially python modules) to lower case.
- Moved views and interfaces into separate hierarchies within each
project, where each top-level directory under the zope package
is a separate project.
- Moved everything to src from lib/python.
lib/python will eventually go away. I need access to the cvs
repository to make this happen, however.
There are probably some bits that are broken. All tests pass
and zope runs, but I haven't tried everything. There are a number
of cleanups I'll work on tomorrow.
=== Zope3/src/zope/configuration/__init__.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:04 2002
+++ Zope3/src/zope/configuration/__init__.py Wed Dec 25 09:13:33 2002
@@ -0,0 +1,37 @@
+##############################################################################
+#
+# 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"]
=== Zope3/src/zope/configuration/action.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:04 2002
+++ Zope3/src/zope/configuration/action.py Wed Dec 25 09:13:33 2002
@@ -0,0 +1,20 @@
+##############################################################################
+#
+# 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$
+"""
+
+def Action(discriminator, callable, args=(), kw={}):
+ return discriminator, callable, args, kw
=== Zope3/src/zope/configuration/exceptions.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:04 2002
+++ Zope3/src/zope/configuration/exceptions.py Wed Dec 25 09:13:33 2002
@@ -0,0 +1,19 @@
+##############################################################################
+#
+# 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
+ """
=== Zope3/src/zope/configuration/hookregistry.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:04 2002
+++ Zope3/src/zope/configuration/hookregistry.py Wed Dec 25 09:13:33 2002
@@ -0,0 +1,143 @@
+##############################################################################
+#
+# 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 types import ModuleType
+from zope.exceptions import DuplicationError, NotFoundError, ZopeError
+from zope.configuration import 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]
=== Zope3/src/zope/configuration/meta.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:04 2002
+++ Zope3/src/zope/configuration/meta.py Wed Dec 25 09:13:33 2002
@@ -0,0 +1,360 @@
+##############################################################################
+#
+# 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$
+"""
+
+
+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
=== Zope3/src/zope/configuration/meta.zcml 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:04 2002
+++ Zope3/src/zope/configuration/meta.zcml Wed Dec 25 09:13:33 2002
@@ -0,0 +1,11 @@
+<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>
=== Zope3/src/zope/configuration/metaconfigure.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:04 2002
+++ Zope3/src/zope/configuration/metaconfigure.py Wed Dec 25 09:13:33 2002
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# 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 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)
+ )
+ ]
=== Zope3/src/zope/configuration/metameta.zcml 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:04 2002
+++ Zope3/src/zope/configuration/metameta.zcml Wed Dec 25 09:13:33 2002
@@ -0,0 +1,54 @@
+<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>
=== Zope3/src/zope/configuration/metametaconfigure.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:04 2002
+++ Zope3/src/zope/configuration/metametaconfigure.py Wed Dec 25 09:13:33 2002
@@ -0,0 +1,71 @@
+##############################################################################
+#
+# 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 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
=== Zope3/src/zope/configuration/metametaconfigurefordocgen.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:05 2002
+++ Zope3/src/zope/configuration/metametaconfigurefordocgen.py Wed Dec 25 09:13:33 2002
@@ -0,0 +1,95 @@
+##############################################################################
+#
+# 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 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}
=== Zope3/src/zope/configuration/metametafordocgen.zcml 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:05 2002
+++ Zope3/src/zope/configuration/metametafordocgen.zcml Wed Dec 25 09:13:33 2002
@@ -0,0 +1,109 @@
+<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>
=== Zope3/src/zope/configuration/name.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:05 2002
+++ Zope3/src/zope/configuration/name.py Wed Dec 25 09:13:33 2002
@@ -0,0 +1,86 @@
+##############################################################################
+#
+# 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$
+"""
+
+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
=== Zope3/src/zope/configuration/xmlconfig.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:05 2002
+++ Zope3/src/zope/configuration/xmlconfig.py Wed Dec 25 09:13:33 2002
@@ -0,0 +1,391 @@
+##############################################################################
+#
+# 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$
+"""
+
+import os
+from zope.configuration import 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]