[Zope-Checkins] CVS: Zope3/lib/python/Zope/Configuration - meta.py:1.1.2.7.6.1 name.py:1.1.2.9.6.1 xmlconfig.py:1.1.2.10.4.1

Barry Warsaw barry@wooz.org
Thu, 21 Mar 2002 19:27:28 -0500


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

Modified Files:
      Tag: contextual-directives
	meta.py name.py xmlconfig.py 
Log Message:
This is work to pass context to zcml directives, so that directives
know where they live.  This is inspired by some suggested changes to
the naming syntax that Stephan and I discussed with Jim.
Specifically, a leading dot, as in

    .JobBoardEx.JobList.

would signify a name relative to the current package, instead of
relative to ZopeProducts.  Also, we'd like to change the trailing dot
to a `+' for signifying "look-the-last-name-up-recursively-until-you-
can't-anymore".  E.g.:

    .JobBoardEx.JobList+

I'm committing this on a branch because it breaks the unit tests and
I'm not sure of the best way to fix the remaining 10 failures.  Jim
suggests that we commit these to the branch so that he can work on
them too.


=== Zope3/lib/python/Zope/Configuration/meta.py 1.1.2.7 => 1.1.2.7.6.1 ===
 from ConfigurationDirectiveInterfaces import INonEmptyDirective
 from ConfigurationDirectiveInterfaces import ISubdirectiveHandler
-from name import resolve
 
 
 _directives = {}
@@ -34,15 +33,15 @@
     directives[name] = subdirs
     return subdirs
 
-def _exe(callable, subs, kw):
-    r = callable(**kw)
+def _exe(callable, subs, context, kw):
+    r = callable(context, **kw)
 
     if subs or INonEmptyDirective.isImplementedBy(callable):
         return r, subs
     else:
         return lambda: r, subs
 
-def begin(_custom_directives, _name, **kw):
+def begin(_custom_directives, _name, context, **kw):
     if _custom_directives and (_name in _custom_directives):
         callable, subs = _custom_directives[_name]
     else:
@@ -51,9 +50,9 @@
         except KeyError:
             raise InvalidDirective(_name)
 
-    return _exe(callable, subs, kw)
+    return _exe(callable, subs, context, kw)
 
-def sub(subs, _name, **kw):
+def sub(subs, _name, context, **kw):
 
     base, subdirs = subs
     
@@ -64,7 +63,7 @@
 
     callable = getattr(base, _name[1])
 
-    return _exe(callable, subs, kw)
+    return _exe(callable, subs, context, kw)
 
 defaultkw = ({},)
 def end(base):
@@ -83,16 +82,17 @@
     def __init__(self, namespace):
         self._namespace = namespace
 
-    def directive(self, name, handler, attributes='', namespace=None):
+    def directive(self, _context, name, handler, attributes='',
+                  namespace=None):
         namespace = namespace or self._namespace
-        subs = register((namespace, name), resolve(handler))
+        subs = register((namespace, name), _context.resolve(handler))
         return Subdirective(subs, namespace)
 
     def __call__(self):
         return ()
 
-def Directive(namespace, name, handler, attributes=''):
-    subs = register((namespace, name), resolve(handler))
+def Directive(_context, namespace, name, handler, attributes=''):
+    subs = register((namespace, name), _context.resolve(handler))
     return Subdirective(subs, namespace)
 
 Directive.__implements__ = INonEmptyDirective
@@ -114,7 +114,7 @@
         self._subs = subs
         self._namespace = namespace
 
-    def subdirective(self, name, attributes='', namespace=None):
+    def subdirective(self, _context, name, attributes='', namespace=None):
         namespace = namespace or self._namespace
         if not namespace:
             raise InvaliDirectiveDefinition(name)


=== Zope3/lib/python/Zope/Configuration/name.py 1.1.2.9 => 1.1.2.9.6.1 ===
 from types import ModuleType
 
-def resolve(name, _silly=('__doc__',), _globals={}):
+def resolve(name, package='ZopeProducts', _silly=('__doc__',), _globals={}):
     if name.startswith('.'):
-        name='ZopeProducts'+name
+        name=package+name
 
-    if name.endswith('.'):
+    if name.endswith('.') or name.endswith('+'):
         name = name[:-1]
         repeat = 1
     else:


=== Zope3/lib/python/Zope/Configuration/xmlconfig.py 1.1.2.10 => 1.1.2.10.4.1 ===
     __top_name = 'http://namespaces.zope.org/zope', 'zopeConfigure' 
 
-    def __init__(self, actions, level=None, directives=None):
+    def __init__(self, actions, context, directives=None):
         self.__stack = []
-        self.__level = level
         self.__actions = actions
         self.__directives = directives
+        self.__context = context
+        context.resolve
 
     def setDocumentLocator(self, locator):
         self.__locator=locator
@@ -85,7 +86,8 @@
 
         if len(stack) == 1:
             try:                
-                stack.append(begin(self.__directives, name, **kw))
+                stack.append(begin(self.__directives, name, self.__context,
+                                   **kw))
             except Exception, v:
                 raise ZopeXMLConfigurationError, (
                     self.__locator, v), sys.exc_info()[2] 
@@ -96,7 +98,7 @@
                 raise ZopeXMLConfigurationError(self.__locator,
                                                 'Invalid sub-directive')
             try:
-                stack.append(sub(subs, name, **kw))
+                stack.append(sub(subs, name, self.__context, **kw))
             except Exception, v:
                 raise ZopeXMLConfigurationError, (
                     self.__locator, v), sys.exc_info()[2] 
@@ -117,7 +119,7 @@
 
         try:
             for des, callable, args, kw in actions:
-                append((self.__level,
+                append((self.__context,
                         (self.__locator.getLineNumber(),
                          self.__locator.getColumnNumber(),
                          self.__locator.getSystemId(),
@@ -141,7 +143,25 @@
         and% at line %s column %s of %s
         """ % ((self.des,) + self.l1 + self.l2)
 
-def xmlconfig(file, actions=None, level=None, directives=None):
+class Context:
+    def __init__(self, stack, module=None):
+        self.__stackcopy = tuple(stack)
+        if module is None:
+            self.__package = 'ZopeProducts'
+        else:
+            self.__package = module.__name__
+
+    def _stackcopy(self):
+        return self.__stackcopy
+
+    def resolve(self, dottedname):
+        name.resolve(dottedname, self.__package)
+
+
+def xmlconfig(file, actions=None, context=None, directives=None):
+    if context is None:
+        context = name
+
     if actions is None:
         call=actions=[]
     else:
@@ -150,7 +170,8 @@
     src=InputSource(getattr(file, 'name', '<string>'))
     src.setByteStream(file)
     parser=make_parser()
-    parser.setContentHandler(ConfigurationHandler(actions, level, directives))
+    parser.setContentHandler(ConfigurationHandler(actions, context,
+                                                  directives))
     parser.setFeature(feature_namespaces, 1)
     parser.parse(src)
 
@@ -186,22 +207,22 @@
 
         f = open(file_name)
         self._stack=[file_name]
-        xmlconfig(f, self._actions, tuple(self._stack), self._directives)
+        xmlconfig(f, self._actions, Context(self._stack), self._directives)
         f.close()
 
-    def include(self, file, package=None):
+    def include(self, _context, file, package=None):
         if package is not None:
             try:
-                module = name.resolve(package)
-                if len(module.__path__) != 1:
+                package = _context.resolve(package)
+                if len(package.__path__) != 1:
                     print ("Module Path: '%s' has wrong number of elements"
-                            % str(module.__path__))
+                            % 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 module.__file__, and lop the tail off that.
-                prefix = module.__path__[0]
+                # use package.__file__, and lop the tail off that.
+                prefix = package.__path__[0]
             except (ImportError, AttributeError, ValueError):
                 raise ValueError, "Invalid package attribute: %s" % package
         else:
@@ -211,7 +232,8 @@
 
         f = open(file_name)
         self._stack.append(file_name)
-        xmlconfig(f, self._actions, tuple(self._stack), self._directives)
+        xmlconfig(f, self._actions, Context(self._stack, package),
+                  self._directives)
         self._stack.pop()
         f.close()
         return ()