[z3-checkins] r15153 - in z3/zopejam/trunk/src: zcmledit zopejam

hathawsh at codespeak.net hathawsh at codespeak.net
Wed Jul 27 09:55:32 CEST 2005


Author: hathawsh
Date: Wed Jul 27 09:55:27 2005
New Revision: 15153

Modified:
   z3/zopejam/trunk/src/zcmledit/configfile.py
   z3/zopejam/trunk/src/zcmledit/directives.py
   z3/zopejam/trunk/src/zcmledit/inspector.py
   z3/zopejam/trunk/src/zcmledit/interfaces.py
   z3/zopejam/trunk/src/zcmledit/project.py
   z3/zopejam/trunk/src/zopejam/main.py
Log:
Made zcmledit aware of configuration contexts and "usedIn" attributes.

As a result, zcmledit can now understand grouping directives, 
complex directives, and subdirectives.



Modified: z3/zopejam/trunk/src/zcmledit/configfile.py
==============================================================================
--- z3/zopejam/trunk/src/zcmledit/configfile.py	(original)
+++ z3/zopejam/trunk/src/zcmledit/configfile.py	Wed Jul 27 09:55:27 2005
@@ -31,7 +31,6 @@
         # used for including this config file
         self.package_name = package_name
 
-
     def load(self):
         """Parse the file into a tree of Elements.
 
@@ -77,22 +76,10 @@
         finally:
             f.close()
 
-
     def createDirective(self, element):
         """Returns an IDirective to fit an XML element"""
         ns, localname = element.name
-
-        if localname == 'configure':
-            t = directives.ConfigureDirective
-        elif localname in ('include', 'includeOverrides'):
-            t = directives.IncludeDirective
-        elif ns == directives.meta_ns and localname in (
-            'directive', 'groupingDirective',
-            'complexDirective', 'simpleDirective'):
-            t = directives.DefinitionDirective
-        else:
-            t = directives.CommonDirective
-
+        t = directives.get_directive_factory(ns, localname)
         return t(element)
 
     def getAbbreviatedFilename(self, trim_default=True):

Modified: z3/zopejam/trunk/src/zcmledit/directives.py
==============================================================================
--- z3/zopejam/trunk/src/zcmledit/directives.py	(original)
+++ z3/zopejam/trunk/src/zcmledit/directives.py	Wed Jul 27 09:55:27 2005
@@ -13,8 +13,9 @@
 from zcmledit.exceptions import NameResolutionError, NoPackageError
 from zcmledit.exceptions import InvalidRelativeNameError, MissingPackageError
 
-meta_ns = u"http://namespaces.zope.org/meta"
+meta_ns = u'http://namespaces.zope.org/meta'
 nzo_prefix = 'http://namespaces.zope.org/'
+default_config_context = 'zope.configuration.interfaces.IConfigurationContext'
 
 
 class Directive(object):
@@ -63,14 +64,51 @@
             return self._abs_package
         return self.getInheritedPackageName()
 
+    def resolveNameAttribute(self, attr, required=False, default=None):
+        """Resolves a dotted name from an attribute"""
+        value = getattr(self, attr)
+        if value:
+            if value.startswith('.'):
+                try:
+                    abs_package = self.getAbsolutePackageName()
+                    return join_package(abs_package, value)
+                except NameResolutionError, e:
+                    self.errors.append(
+                        '%s: %s' % (e.__class__.__name__, str(e)))
+                    return None
+            else:
+                return value
+        elif required:
+            self.errors.append("Missing attribute: '%s'" % attr)
+        return default
+
     def getType(self):
-        """Returns an IDefinitionDirective or None"""
-        project = self.element.config_file.project
+        """Returns an IDefinitionDirective instance or None"""
+        if self.element.parent is not None:
+            parent_type = self.element.parent.directive.getType()
+            if parent_type is None:
+                # The parent directive has no definition
+                return None
+            context_iface_names, complex_parent = parent_type.getContextInfo()
+        else:
+            context_iface_names = [default_config_context]
+            complex_parent = None
         if interfaces.IGenericNamespaceDirective.providedBy(self):
-            ns, localname = self.element.name
-            return project.definitions.get(('*', localname))
+            my_name = ('*', self.element.name[1])
         else:
-            return project.definitions.get(self.element.name)
+            my_name = self.element.name
+
+        # Find the definition most specific to the configuration context
+        project = self.element.config_file.project
+        for iface_name in context_iface_names:
+            iface = project.interfaces[iface_name]
+            inames = [iface_name] + [i.name for i in iface.sro]
+            for iname in inames:
+                key = (iname, complex_parent, my_name)
+                dfn = project.definitions.get(key)
+                if dfn is not None:
+                    return dfn
+        return None
 
     def getTypeName(self):
         """Returns a type name like 'http://namespaces.zope.org/zope:view'"""
@@ -192,6 +230,18 @@
     def readElement(self):
         self.errors = []
         self.name = self.element.data.get('name')
+        self.used_in = self.element.data.get('used_in')
+        if self.name in ['configure', 'include', 'includeOverrides']:
+            # Although zope.configuration probably has no trouble with
+            # a directive that overloads these names, this package
+            # reads configuration files outside a configuration
+            # execution context.  Without that context, it can only
+            # assume that these special names are never overloaded.
+            # The exception below tries to ensure the assumption
+            # never breaks.
+            raise RuntimeError(
+                "Unable to define directives named '%s' at this time."
+                % self.name)
         self.schema = self.element.data.get('schema')
 
         ns = None
@@ -205,26 +255,119 @@
         if ns is None:
             ns = self.element.data.get('namespace')
 
-        self.fullname = (ns, self.name)
-        if self.schema:
-            if self.schema.startswith('.'):
-                try:
-                    abs_package = self.getAbsolutePackageName()
-                    abs_schema = join_package(abs_package, self.schema)
-                except NameResolutionError, e:
-                    abs_schema = None
-                    self.errors.append(
-                        '%s: %s' % (e.__class__.__name__, str(e)))
-            else:
-                abs_schema = self.schema
-        else:
-            self.errors.append("Missing 'schema' attribute")
-        self.abs_schema = abs_schema
+        self.provided_name = (ns, self.name)
+        self.abs_schema = self.resolveNameAttribute('schema', required=True)
+        self.abs_used_in = self.resolveNameAttribute(
+            'used_in', required=False, default=default_config_context)
 
     def getSchemaInfo(self):
         project = self.element.config_file.project
         return project.interfaces[self.abs_schema]
 
+    def getContextInfo(self):
+        """Returns directive context information.
+
+        Used for discovering the type of a contained directive.
+        Returns (context_interface_names, complex_directive_name).
+        """
+        # a non-grouping directive should not contain any directives,
+        # so return empty context information.
+        return ([], None)
+
+    def getProvidedName(self):
+        """Returns the name of the provided directive as a tuple"""
+        return self.provided_name
+
+    def getDefinitionKey(self):
+        """Returns the key for this directive in project.definitions.
+
+        The key is a tuple: (used_in, complex_parent_name, provided_name).
+        """
+        return (self.abs_used_in, None, self.provided_name)
+
+    def getRequiredInterfaceNames(self):
+        """Returns the interface names this definition depends upon"""
+        res = []
+        if self.abs_schema:
+            res.append(self.abs_schema)
+        if self.abs_used_in:
+            res.append(self.abs_used_in)
+        return res
+
+    def getRequiredClassNames(self):
+        """Returns the class names this definition depends upon"""
+        return []
+
+
+class ComplexDefinitionDirective(DefinitionDirective):
+    """A complexDirective."""
+    implements(interfaces.IComplexDefinitionDirective)
+
+    context_iface = 'zope.configuration.config.IComplexDirectiveContext'
+
+    def getRequiredInterfaceNames(self):
+        """Returns the class names this definition depends upon"""
+        base = super(ComplexDefinitionDirective, self)
+        return base.getRequiredInterfaceNames() + [self.context_iface]
+
+    def getContextInfo(self):
+        """Returns directive context information.
+
+        Used for discovering the type of a contained directive.
+        Returns (context_interface_names, complex_directive_name).
+        """
+        return ([self.context_iface], self.getProvidedName())
+
+
+class SubdirectiveDefinitionDirective(DefinitionDirective):
+    """A subdirective."""
+    def readElement(self):
+        super(SubdirectiveDefinitionDirective, self).readElement()
+
+        self.complex_parent_name = None
+        parent = self.element.parent
+        icomplex = interfaces.IComplexDefinitionDirective
+        if parent is None or not icomplex.providedBy(parent.directive):
+            self.errors.append(
+                'subdirective defined outside a complexDirective')
+        else:
+            self.complex_parent_name = parent.directive.getProvidedName()
+
+    def getDefinitionKey(self):
+        """Returns the key for this directive in project.definitions.
+
+        The key is a tuple: (used_in, complex_parent_name, provided_name).
+        """
+        return (self.abs_used_in, self.complex_parent_name, self.provided_name)
+
+
+class GroupingDefinitionDirective(DefinitionDirective):
+    """A groupingDirective."""
+    def readElement(self):
+        super(GroupingDefinitionDirective, self).readElement()
+        self.handler = self.element.data.get('handler')
+        self.abs_handler = self.resolveNameAttribute('handler', required=True)
+
+    def getRequiredClassNames(self):
+        """Returns the class names this definition depends upon"""
+        if self.abs_handler:
+            return [self.abs_handler]
+        return []
+
+    def getContextInfo(self):
+        """Returns directive context information.
+
+        Used for discovering the type of a contained directive.
+        Returns (context_interface_names, complex_directive_name).
+        """
+        if self.abs_handler:
+            project = self.element.config_file.project
+            class_info = project.classes[self.abs_handler]
+            impl = class_info.implements_names
+            return (list(impl), None)
+        else:
+            return ([], None)
+
 
 class BootstrapDirective(Directive):
     """A bootstrap definition directive.
@@ -233,15 +376,17 @@
     """
     implements(interfaces.IDefinitionDirective)
 
-    def __init__(self, project, ns, name, abs_schema):
+    def __init__(self, project, ns, name, abs_schema,
+                 usedIn=default_config_context):
         self.project = project
         self.element = None
         self.errors = ()
 
         self.name = name
-        self.fullname = (ns, name)
+        self.provided_name = (ns, name)
         self.schema = abs_schema
         self.abs_schema = abs_schema
+        self.abs_used_in = usedIn
 
     def getAbsolutePackageName(self):
         return None
@@ -249,22 +394,96 @@
     def getSchemaInfo(self):
         return self.project.interfaces[self.abs_schema]
 
+    def getProvidedName(self):
+        """Returns the name of the provided directive as a tuple"""
+        return self.provided_name
+
+    def getDefinitionKey(self):
+        """Returns the key for this directive in project.definitions.
+
+        The key is a tuple: (used_in, complex_parent_name, provided_name).
+        """
+        return (default_config_context, None, self.provided_name)
+
+    def getRequiredInterfaceNames(self):
+        """Returns the interface names this definition depends upon"""
+        return [self.abs_schema]
+
+    def getRequiredClassNames(self):
+        """Returns the class names this definition depends upon"""
+        return []
+
+    def getType(self):
+        raise NotImplementedError
+
     def getTypeName(self):
         """Returns a type name like 'http://namespaces.zope.org/zope:view'"""
-        return '%s:%s' % self.fullname
+        return nzo_prefix + 'meta:directive'
 
     def getAbbreviatedTypeName(self):
         """Returns a shortened directive type name like 'zope:view'"""
-        name = self.getTypeName()
-        if name.startswith(nzo_prefix):
-            name = name[len(nzo_prefix):]
-        return name
+        return 'meta:directive'
+
+
+class BootstrapGroupingDirective(BootstrapDirective):
+    """A bootstrap grouping definition directive."""
+    
+    def __init__(self, project, ns, name, abs_schema, abs_handler,
+                 usedIn=default_config_context):
+        super(BootstrapGroupingDirective, self).__init__(
+            project, ns, name, abs_schema, usedIn=usedIn)
+        self.abs_handler = abs_handler
+
+    def getRequiredClassNames(self):
+        """Returns the class names this definition depends upon"""
+        return [self.abs_handler]
+
+    def getContextInfo(self):
+        """Returns directive context information.
+
+        Used for discovering the type of a contained directive.
+        Returns (context_interface_names, complex_directive_name).
+        """
+        class_info = self.project.classes[self.abs_handler]
+        impl = class_info.implements_names
+        return (list(impl), None)
+
+    def getType(self):
+        raise NotImplementedError
+
+    def getTypeName(self):
+        """Returns a type name like 'http://namespaces.zope.org/zope:view'"""
+        return nzo_prefix + 'meta:groupingDirective'
+
+    def getAbbreviatedTypeName(self):
+        """Returns a shortened directive type name like 'zope:view'"""
+        return 'meta:groupingDirective'
 
 
 class CommonDirective(Directive):
     implements(interfaces.IDirective)
 
 
+meta_factories = {
+    'directive': DefinitionDirective,
+    'groupingDirective': GroupingDefinitionDirective,
+    'complexDirective': ComplexDefinitionDirective,
+    'subdirective': SubdirectiveDefinitionDirective,
+    }
+
+
+def get_directive_factory(ns, localname):
+    if localname == 'configure':
+        return ConfigureDirective
+    elif localname in ('include', 'includeOverrides'):
+        return IncludeDirective
+    elif ns == meta_ns:
+        t = meta_factories.get(localname)
+        if t is not None:
+            return t
+    return CommonDirective
+
+
 def join_package(parent, child):
     """Joins an absolute package name with a relative object name."""
     if child == '.':

Modified: z3/zopejam/trunk/src/zcmledit/inspector.py
==============================================================================
--- z3/zopejam/trunk/src/zcmledit/inspector.py	(original)
+++ z3/zopejam/trunk/src/zcmledit/inspector.py	Wed Jul 27 09:55:27 2005
@@ -13,14 +13,34 @@
 import cPickle
 import os
 import sys
+from types import ClassType
 
+from zope.interface import implementedBy
 from zope.interface.interfaces import IInterface
 
 _import_chickens = {}, {}, ("*",) # dead chickens needed by __import__
 
 
-def inspect_interfaces(names):
-    """Returns {name: {'doc', 'bases', 'sro', 'attrs' | 'error'}}"""
+def inspect_globals(class_names, iface_names):
+    """Returns information about named classes and interfaces."""
+    classes = inspect_classes(class_names)
+
+    # also inspect the interfaces implemented by the class
+    iface_names = list(iface_names)  # make a copy
+    for class_info in classes.values():
+        names = class_info.get('implements')
+        if names:
+            iface_names.extend(names)
+
+    ifaces = inspect_interfaces(iface_names)
+    return (classes, ifaces)
+
+
+def inspect_classes(names):
+    """Returns information about named classes.
+
+    Returns {name: {'doc','bases','mro','implements','attributes'|'error'}}
+    """
     res = {}
     # the names are absolute.
     todo = list(names)
@@ -31,55 +51,127 @@
         info = {}
         res[name] = info
 
-        pos = name.rfind('.')
-        if pos >= 0:
-            mname = name[:pos]
-            oname = name[pos + 1:]
-        else:
-            mname = ''
-            oname = name
+        try:
+            obj = import_name(name)
+        except:
+            info['error'] = str(sys.exc_info()[1])
+            continue
+
+        info['doc'] = getattr(obj, '__doc__', None)
+
+        if not isinstance(obj, (type, ClassType)):
+            info['error'] = "'%s' is not a class" % name
+            continue
+
+        # report implemented interfaces
+        impl = []
+        for iface in implementedBy(obj):
+            fullname = get_name(iface)
+            if fullname:
+                impl.append(fullname)
+        info['implements'] = impl
+
+        # report base classes
+        bases = []
+        for base in getattr(obj, '__bases__', ()):
+            fullname = get_name(base)
+            if fullname:
+                bases.append(fullname)
+                if not res.has_key(fullname):
+                    todo.append(fullname)
+        info['bases'] = bases
+
+        # report method resolution order
+        mro = []
+        for base in getattr(obj, '__mro__', ()):
+            fullname = get_name(base)
+            if fullname:
+                mro.append(fullname)
+        info['mro'] = mro
+
+        attrs = {}
+        for n in getattr(obj, '__dict__', {}).keys():
+            if hasattr(obj, n):
+                attr = getattr(obj, n)
+                ainfo = {'doc': getattr(attr, '__doc__', None)}
+                attrs[n] = ainfo
+        info['attributes'] = attrs
+    return res
+    
+
+def inspect_interfaces(names):
+    """Returns information about named interfaces.
+
+    Returns {name: {'doc', 'bases', 'sro', 'attributes' | 'error'}}
+    """
+    res = {}
+    # the names are absolute.
+    todo = list(names)
+    while todo:
+        name = todo.pop()
+        if res.has_key(name):
+            continue
+        info = {}
+        res[name] = info
 
         try:
-            module = __import__(mname, *_import_chickens)
-            obj = getattr(module, oname)
+            obj = import_name(name)
         except:
             info['error'] = str(sys.exc_info()[1])
             continue
 
-        if IInterface.providedBy(obj):
-            info['doc'] = getattr(obj, '__doc__', None)
+        if not IInterface.providedBy(obj):
+            info['error'] = "'%s' is not an interface" % name
+            continue
 
-            # report base interfaces
-            bases = []
-            for base in getattr(obj, '__bases__', ()):
-                m = getattr(base, '__module__', None)
-                n = getattr(base, '__name__', None)
-                if m and n:
-                    fullname = '%s.%s' % (m, n)
-                    bases.append(fullname)
-                    if not res.has_key(fullname):
-                        todo.append(fullname)
-            info['bases'] = bases
-
-            # report specification resolution order
-            sro = []
-            for base in getattr(obj, '__sro__', ()):
-                m = getattr(base, '__module__', None)
-                n = getattr(base, '__name__', None)
-                if m and n:
-                    fullname = '%s.%s' % (m, n)
-                    sro.append(fullname)
-            info['sro'] = sro
-
-            attrs = {}
-            for n in obj.names(False):
-                attrs[n] = obj[n]
-            info['attributes'] = attrs
-        else:
-            info['error'] = 'not an interface; type is %s' % str(type(obj))
+        info['doc'] = getattr(obj, '__doc__', None)
+
+        # report base interfaces
+        bases = []
+        for base in getattr(obj, '__bases__', ()):
+            fullname = get_name(base)
+            if fullname:
+                bases.append(fullname)
+                if not res.has_key(fullname):
+                    todo.append(fullname)
+        info['bases'] = bases
+
+        # report specification resolution order
+        sro = []
+        for base in getattr(obj, '__sro__', ()):
+            fullname = get_name(base)
+            if fullname:
+                sro.append(fullname)
+        info['sro'] = sro
+
+        attrs = {}
+        for n in obj.names(False):
+            attrs[n] = obj[n]
+        info['attributes'] = attrs
     return res
 
 
+def import_name(name):
+    pos = name.rfind('.')
+    if pos >= 0:
+        mname = name[:pos]
+        oname = name[pos + 1:]
+    else:
+        mname = ''
+        oname = name
+
+    module = __import__(mname, *_import_chickens)
+    return getattr(module, oname)
+
+
+def get_name(obj):
+    m = getattr(obj, '__module__', None)
+    n = getattr(obj, '__name__', None)
+    if m and n:
+        return '%s.%s' % (m, n)
+    return None
+
+
 def main():
     # pickle in, pickle out.
     funcname, args, kwargs = cPickle.load(sys.stdin)

Modified: z3/zopejam/trunk/src/zcmledit/interfaces.py
==============================================================================
--- z3/zopejam/trunk/src/zcmledit/interfaces.py	(original)
+++ z3/zopejam/trunk/src/zcmledit/interfaces.py	Wed Jul 27 09:55:27 2005
@@ -17,5 +17,8 @@
 class IDefinitionDirective(IDirective):
     pass
 
+class IComplexDefinitionDirective(IDefinitionDirective):
+    pass
+
 class IProject(Interface):
     pass

Modified: z3/zopejam/trunk/src/zcmledit/project.py
==============================================================================
--- z3/zopejam/trunk/src/zcmledit/project.py	(original)
+++ z3/zopejam/trunk/src/zcmledit/project.py	Wed Jul 27 09:55:27 2005
@@ -33,37 +33,116 @@
             pythonpath = [os.path.join(self.base, 'src')] + sys.path
         self.pythonpath = pythonpath
 
-    def createBootstrapDirectives(self):
-        """Returns a dictionary containing the bootstrap definitions"""
-        res = {}
-        meta_ns = directives.meta_ns
-        for ns, name, schema in [
-            ('*', 'configure',
-             "zope.configuration.zopeconfigure.IZopeConfigure"),
-            ('*', 'include', "zope.configuration.xmlconfig.IInclude"),
-            ('*', 'includeOverrides', "zope.configuration.xmlconfig.IInclude"),
-            (meta_ns, 'directive',
-             "zope.configuration.config.IFullInfo"),
-            (meta_ns, 'groupingDirective',
-             "zope.configuration.config.IFullInfo"),
-            (meta_ns, 'directives',
-             "zope.configuration.config.IDirectivesInfo"),
-            (meta_ns, 'complexDirective',
-             "zope.configuration.config.IFullInfo"),
-            (meta_ns, 'subdirective',
-             "zope.configuration.config.IDirectiveInfo"),
-            (meta_ns, 'provides',
-             "zope.configuration.config.IProvidesDirectiveInfo"),
-            ]:
-            res[(ns, name)] = directives.BootstrapDirective(
-                self, ns, name, schema)
-        return res
+    def createBootstrapDefinitions(self):
+        """fills self.directives with the bootstrap definition directives"""
+
+        self.definitions = {}
+        # self.directives contains:
+        # {definition_key: IDirectiveDefinition}
+        # where definition_key == (used_in, complex_parent, provided_name).
+        # complex_parent and provided_name each contain (ns, localname),
+        # although complex_parent is None except when defining a
+        # subdirective.  used_in is an interface name.
+
+        def defineGeneric(name, schema):
+            d = directives.BootstrapDirective(
+                self, '*', name, schema)
+            self.definitions[d.getDefinitionKey()] = d
+
+        def defineGroupingGeneric(name, schema, handler_class):
+            d = directives.BootstrapGroupingDirective(
+                self, '*', name, schema, handler_class)
+            self.definitions[d.getDefinitionKey()] = d
+
+        def defineDirective(
+            name, schema, usedIn=directives.default_config_context):
+            ns = directives.meta_ns
+            d = directives.BootstrapDirective(
+                self, ns, name, schema, usedIn=usedIn)
+            self.definitions[d.getDefinitionKey()] = d
+
+        def defineGroupingDirective(
+                name, schema, handler_class,
+                usedIn=directives.default_config_context):
+            ns = directives.meta_ns
+            d = directives.BootstrapGroupingDirective(
+                self, ns, name, schema, handler_class, usedIn=usedIn)
+            self.definitions[d.getDefinitionKey()] = d
+
+        module = 'zope.configuration.config'
+
+        # The following initialization is based on
+        # zope.configuration.xmlconfig.registerCommonDirectives().
+
+        defineGroupingGeneric(
+            'configure',
+            'zope.configuration.zopeconfigure.IZopeConfigure',
+            'zope.configuration.zopeconfigure.ZopeConfigure')
+
+        defineGeneric(
+            'include',
+            'zope.configuration.xmlconfig.IInclude')
+
+        defineGeneric(
+            'includeOverrides',
+            'zope.configuration.xmlconfig.IInclude')
+
+        # The following initialization is based on
+        # zope.configuration.config._bootstrap().
+
+        # Define the directive (simple directive) directive
+        defineDirective(
+            'directive',
+            module + '.IStandaloneDirectiveInfo')
+
+        # Standalone groupingDirective
+        defineDirective(
+            'groupingDirective',
+            module + '.IStandaloneDirectiveInfo')
+
+        # define the directives directive
+        defineGroupingDirective(
+            'directives',
+            module + '.IDirectivesInfo',
+            module + '.DirectivesHandler')
+
+        # directive and groupingDirective inside directives
+        defineDirective(
+            'directive',
+            module + '.IFullInfo',
+            usedIn = module + '.IDirectivesContext')
+        defineDirective(
+            'groupingDirective',
+            module + '.IFullInfo',
+            usedIn = module + '.IDirectivesContext')
+
+        # Set up complex directive directive, both standalone, and in
+        # directives directive
+        defineGroupingDirective(
+            'complexDirective',
+            module + '.IStandaloneDirectiveInfo',
+            module + '.ComplexDirectiveDefinition')
+        defineGroupingDirective(
+            'complexDirective',
+            module + '.IFullInfo',
+            module + '.ComplexDirectiveDefinition',
+            usedIn = module + '.IDirectivesContext')
+
+        # Finally, set up subdirective directive
+        defineDirective(
+            'subdirective',
+            module + '.IDirectiveInfo',
+            usedIn = module + '.IComplexDirectiveContext')
+
+        # meta:provides
+        defineDirective(
+            'provides',
+            module + '.IProvidesDirectiveInfo')
 
     def load(self):
+        self.createBootstrapDefinitions()
         self.packages = {}  # {package name: [filename]}
         self.files = {}     # {filename: config_file}
-        # self.definitions contains {(ns, localname): IDirectiveDefinition}
-        self.definitions = self.createBootstrapDirectives()
         self.root_config = ConfigurationFile(self, self.root_filename)
         self.files[self.root_filename] = self.root_config
 
@@ -90,21 +169,41 @@
 
             # add to self.definitions
             for dfn in cfg.definitions:
-                if self.definitions.has_key(dfn.fullname):
-                    raise RuntimeError("can't handle multiple definitions for "
-                                       "directive %s" % repr(dfn.fullname))
-                self.definitions[dfn.fullname] = dfn
-
-        self.load_schemas()
-
-    def load_schemas(self):
-        names = [dfn.abs_schema for dfn in self.definitions.values()]
-        d = self.call_inspector('inspect_interfaces', names)
+                key = dfn.getDefinitionKey()
+                if self.definitions.has_key(key):
+                    # Conflicting metadirectives.
+                    # Panic for now, but in the future, this could
+                    # instead set an error on the existing directive.
+                    raise RuntimeError(
+                        'metadirective conflict on %s' % repr(key))
+                self.definitions[key] = dfn
+
+        self.load_globals()
+
+    def load_globals(self):
+        """Fill self.interfaces and self.classes"""
+        class_names = set()
+        iface_names = set()
+        iface_names.add(directives.default_config_context)
+
+        for dfn in self.definitions.values():
+            class_names.update(dfn.getRequiredClassNames())
+            iface_names.update(dfn.getRequiredInterfaceNames())
+
+        c, i = self.call_inspector(
+            'inspect_globals', list(class_names), list(iface_names))
+
+        self.classes = {}
         self.interfaces = {}
-        for name, info in d.items():
+        for name, info in c.items():
+            self.classes[name] = ClassInfo(name, info)
+        for name, info in i.items():
             self.interfaces[name] = InterfaceInfo(name, info)
+
         for info in self.interfaces.values():
             info.initBases(self.interfaces)
+        for info in self.classes.values():
+            info.initBases(self.classes, self.interfaces)
 
     def call_inspector(self, funcname, *args, **kw):
         inspector_py = os.path.join(here, 'inspector.py')
@@ -148,6 +247,28 @@
         return p
 
 
+class ClassInfo:
+    """Contains info received from inspector.inspect_classes()."""
+
+    def __init__(self, name, info):
+        self.name = name
+        self.error = info.get('error', '')
+        self.doc = info.get('doc', '')
+        self.implements_names = info.get('implements', ())
+        self.base_names = info.get('bases', ())
+        self.mro_names = info.get('mro', ())
+        self.attributes = info.get('attributes')
+        if self.attributes is None:
+            self.attributes = {}
+
+    def initBases(self, all_classes, all_interfaces):
+        """As part of construction, link with base objects."""
+        self.bases = [all_classes[name] for name in self.base_names]
+        self.mro = [all_classes[name] for name in self.mro_names]
+        self.implements = [all_interfaces[name]
+                           for name in self.implements_names]
+
+
 class InterfaceInfo:
     """Contains info received from inspector.inspect_interfaces()."""
 
@@ -166,7 +287,7 @@
                 self.fields[k] = FieldInfo(self, k, v)
 
     def initBases(self, all_interfaces):
-        """As part of construction, link with base InterfaceInfo objects."""
+        """As part of construction, link with base objects."""
         self.bases = [all_interfaces[name] for name in self.base_names]
         self.sro = [all_interfaces[name] for name in self.sro_names]
 

Modified: z3/zopejam/trunk/src/zopejam/main.py
==============================================================================
--- z3/zopejam/trunk/src/zopejam/main.py	(original)
+++ z3/zopejam/trunk/src/zopejam/main.py	Wed Jul 27 09:55:27 2005
@@ -25,7 +25,7 @@
 
 here = os.path.abspath(os.path.dirname(__file__))
 
-add_menu_ids = {}  # {id -> (ns, localname)}
+add_menu_ids = {}  # {id -> definition_key}
 
 
 class PaletteImageList(wx.ImageList):
@@ -289,33 +289,33 @@
 
         # create reverse_menu_ids from add_menu_ids
         reverse_menu_ids = {}
-        for item_id, fullname in add_menu_ids.items():
-            reverse_menu_ids[fullname] = item_id
+        for item_id, key in add_menu_ids.items():
+            reverse_menu_ids[key] = item_id
 
         # figure out what should go in the add menu
-        options = {}  # {(label, namespace): [(localname, item_id)]}
-        for fullname in self.project.definitions.keys():
-            item_id = reverse_menu_ids.get(fullname)
+        submenus = {}  # {(label, namespace): [(localname, item_id)]}
+        for key, dfn in self.project.definitions.items():
+            item_id = reverse_menu_ids.get(key)
             if item_id is None:
                 item_id = wx.NewId()
-                reverse_menu_ids[fullname] = item_id
-                add_menu_ids[item_id] = fullname
-            ns, localname = fullname
+                reverse_menu_ids[key] = item_id
+                add_menu_ids[item_id] = key
+            ns, localname = dfn.getProvidedName()
             if ns.startswith(nzo_prefix):
                 label = ns[len(nzo_prefix):]
             else:
                 label = ns
-            key = (label, ns)
-            names = options.get(key)
+            submenu = (label, ns)
+            names = submenus.get(submenu)
             if names is None:
                 names = []
-                options[key] = names
+                submenus[submenu] = names
             names.append((localname, item_id))
 
-        # add the options to the add menu
-        options = options.items()
-        options.sort()
-        for (label, ns), names in options:
+        # add the submenus to the add menu
+        submenus = submenus.items()
+        submenus.sort()
+        for (label, ns), names in submenus:
             m = wx.Menu()
             names.sort()
             for name, item_id in names:
@@ -326,16 +326,16 @@
     def onMenuHighlight(self, event):
         item_id = event.GetId()
         if item_id > 0:
-            fullname = add_menu_ids.get(item_id)
+            key = add_menu_ids.get(item_id)
         else:
-            fullname = None
-        if not fullname:
+            key = None
+        if not key:
             # hide the tip soon
             if not self.tip_hide_timer.IsRunning():
                 self.tip_hide_timer.Start(300, wx.TIMER_ONE_SHOT)
             return
 
-        dfn = self.project.definitions[fullname]
+        dfn = self.project.definitions[key]
         info = dfn.getSchemaInfo()
         if info.error:
             doc = ('An error occurred while loading the '
@@ -347,7 +347,7 @@
         if not doc:
             doc = 'No documentation available.'
 
-        ns, localname = fullname
+        ns, localname = dfn.getProvidedName()
         if ns.startswith(nzo_prefix):
             label = ns[len(nzo_prefix):]
         else:
@@ -561,7 +561,7 @@
             state = self.GetItemState(i, mask)
             if state:
                 flags[directive_index] = state
-        
+
         # _col and _colSortFlag are defined in ColumnSorterMixin.
         # col is the column which was clicked on and
         # sf, the sort flag, is False for descending (Z->A)


More information about the z3-checkins mailing list