[Checkins] SVN: grok/trunk/src/grok/ Merge faassen-index branch. Add a new component called grok.Indexes.

Martijn Faassen faassen at infrae.com
Fri Apr 20 11:28:55 EDT 2007


Log message for revision 74266:
  Merge faassen-index branch. Add a new component called grok.Indexes. 
  You can subclass from it and initialize indexes for fields/methods on a
  schema, or attributes on a class. This automatically sets up the
  catalog and intid service where needed.
  

Changed:
  U   grok/trunk/src/grok/__init__.py
  U   grok/trunk/src/grok/components.py
  U   grok/trunk/src/grok/directive.py
  A   grok/trunk/src/grok/ftests/catalog/indexes.py
  A   grok/trunk/src/grok/ftests/catalog/indexes_app_interface.py
  A   grok/trunk/src/grok/ftests/catalog/indexes_class.py
  A   grok/trunk/src/grok/ftests/catalog/indexes_module.py
  A   grok/trunk/src/grok/ftests/catalog/indexes_multiple.py
  A   grok/trunk/src/grok/ftests/catalog/indexes_multiple_conflict.py
  A   grok/trunk/src/grok/ftests/catalog/indexes_name.py
  A   grok/trunk/src/grok/ftests/catalog/indexes_no_app.py
  A   grok/trunk/src/grok/ftests/catalog/indexes_nonexistent.py
  A   grok/trunk/src/grok/ftests/catalog/indexes_site.py
  A   grok/trunk/src/grok/index.py
  U   grok/trunk/src/grok/interfaces.py
  U   grok/trunk/src/grok/meta.py

-=-
Modified: grok/trunk/src/grok/__init__.py
===================================================================
--- grok/trunk/src/grok/__init__.py	2007-04-20 15:13:07 UTC (rev 74265)
+++ grok/trunk/src/grok/__init__.py	2007-04-20 15:28:55 UTC (rev 74266)
@@ -34,9 +34,10 @@
 from grok.components import PageTemplate, PageTemplateFile, Container, Traverser
 from grok.components import Site, GlobalUtility, LocalUtility, Annotation
 from grok.components import Application, Form, AddForm, EditForm, DisplayForm
+from grok.components import Indexes
 from grok.directive import (context, name, template, templatedir, provides,
                             baseclass, global_utility, local_utility,
-                            define_permission, require)
+                            define_permission, require, site)
 from grok._grok import do_grok as grok  # Avoid name clash within _grok
 from grok._grok import SubscribeDecorator as subscribe
 from grok.error import GrokError, GrokImportError

Modified: grok/trunk/src/grok/components.py
===================================================================
--- grok/trunk/src/grok/components.py	2007-04-20 15:13:07 UTC (rev 74265)
+++ grok/trunk/src/grok/components.py	2007-04-20 15:28:55 UTC (rev 74266)
@@ -119,8 +119,8 @@
 
 class Application(Site):
     """A top-level application object."""
+    interface.implements(interfaces.IApplication)
 
-
 class Adapter(object):
 
     def __init__(self, context):
@@ -485,3 +485,26 @@
     interface.implementsOnly(interfaces.IGrokForm)
 
     template = default_display_template
+
+class IndexesClass(object):
+    def __init__(self, name, bases=(), attrs=None):
+        if attrs is None:
+            return
+        # make sure we take over a bunch of possible attributes
+        for name in ['__grok_context__', '__grok_name__',
+                     '__grok_site__']:
+            value = attrs.get(name)
+            if value is not None:
+                setattr(self, name, value)
+        # now read and store indexes
+        indexes = {}
+        for name, value in attrs.items():
+            if not interfaces.IIndexDefinition.providedBy(value):
+                continue
+            indexes[name] = value
+        self.__grok_indexes__ = indexes
+        # __grok_module__ is needed to make defined_locally() return True for
+        # inline templates
+        self.__grok_module__ = util.caller_module()
+        
+Indexes = IndexesClass('Indexes')

Modified: grok/trunk/src/grok/directive.py
===================================================================
--- grok/trunk/src/grok/directive.py	2007-04-20 15:13:07 UTC (rev 74265)
+++ grok/trunk/src/grok/directive.py	2007-04-20 15:28:55 UTC (rev 74266)
@@ -277,3 +277,5 @@
 define_permission = MultipleTextDirective('grok.define_permission',
                                           ModuleDirectiveContext())
 require = RequireDirective('grok.require', ClassDirectiveContext())
+site = InterfaceOrClassDirective('grok.site',
+                                 ClassDirectiveContext())

Copied: grok/trunk/src/grok/ftests/catalog/indexes.py (from rev 74265, grok/branches/faassen-index/src/grok/ftests/catalog/indexes.py)

Copied: grok/trunk/src/grok/ftests/catalog/indexes_app_interface.py (from rev 74265, grok/branches/faassen-index/src/grok/ftests/catalog/indexes_app_interface.py)

Copied: grok/trunk/src/grok/ftests/catalog/indexes_class.py (from rev 74265, grok/branches/faassen-index/src/grok/ftests/catalog/indexes_class.py)

Copied: grok/trunk/src/grok/ftests/catalog/indexes_module.py (from rev 74265, grok/branches/faassen-index/src/grok/ftests/catalog/indexes_module.py)

Copied: grok/trunk/src/grok/ftests/catalog/indexes_multiple.py (from rev 74265, grok/branches/faassen-index/src/grok/ftests/catalog/indexes_multiple.py)

Copied: grok/trunk/src/grok/ftests/catalog/indexes_multiple_conflict.py (from rev 74265, grok/branches/faassen-index/src/grok/ftests/catalog/indexes_multiple_conflict.py)

Copied: grok/trunk/src/grok/ftests/catalog/indexes_name.py (from rev 74265, grok/branches/faassen-index/src/grok/ftests/catalog/indexes_name.py)

Copied: grok/trunk/src/grok/ftests/catalog/indexes_no_app.py (from rev 74265, grok/branches/faassen-index/src/grok/ftests/catalog/indexes_no_app.py)

Copied: grok/trunk/src/grok/ftests/catalog/indexes_nonexistent.py (from rev 74265, grok/branches/faassen-index/src/grok/ftests/catalog/indexes_nonexistent.py)

Copied: grok/trunk/src/grok/ftests/catalog/indexes_site.py (from rev 74265, grok/branches/faassen-index/src/grok/ftests/catalog/indexes_site.py)

Copied: grok/trunk/src/grok/index.py (from rev 74265, grok/branches/faassen-index/src/grok/index.py)

Modified: grok/trunk/src/grok/interfaces.py
===================================================================
--- grok/trunk/src/grok/interfaces.py	2007-04-20 15:13:07 UTC (rev 74265)
+++ grok/trunk/src/grok/interfaces.py	2007-04-20 15:28:55 UTC (rev 74266)
@@ -370,3 +370,16 @@
     Used to register applications as utilities to look them up and
     provide a list of grokked applications.
     """
+
+class IIndexDefinition(interface.Interface):
+    """Define an index for grok.Indexes.
+    """
+
+    def setup(catalog, name, context):
+        """Set up index called name in given catalog.
+
+        Use name for index name and attribute to index. Set up
+        index for interface or class context.
+        """
+    
+        

Modified: grok/trunk/src/grok/meta.py
===================================================================
--- grok/trunk/src/grok/meta.py	2007-04-20 15:13:07 UTC (rev 74265)
+++ grok/trunk/src/grok/meta.py	2007-04-20 15:28:55 UTC (rev 74266)
@@ -15,6 +15,13 @@
 from zope.app.container.interfaces import INameChooser
 from zope.app.container.contained import contained
 
+from zope.app.intid import IntIds
+from zope.app.intid.interfaces import IIntIds
+from zope.app.catalog.catalog import Catalog
+from zope.app.catalog.interfaces import ICatalog
+
+from zope.exceptions.interfaces import DuplicationError
+
 import grok
 from grok import util, components, formlib
 from grok.error import GrokError
@@ -377,34 +384,51 @@
 
     for info in util.class_annotation(site.__class__,
                                       'grok.utilities_to_install', []):
-        utility = info.factory()
-        site_manager = site.getSiteManager()
+        setupUtility(site, info.factory(), info.provides, name=info.name,
+                     name_in_container=info.name_in_container,
+                     public=info.public, setup=info.setup)
 
-        # store utility
-        if not info.public:
-            container = site_manager
-        else:
-            container = site
+    # we are done. If this subscriber gets fired again, we therefore
+    # do not register utilities anymore
+    site.__grok_utilities_installed__ = True
 
-        name_in_container = info.name_in_container 
-        if name_in_container is None:
-            name_in_container = INameChooser(container).chooseName(
-                info.factory.__name__, utility)
-        container[name_in_container] = utility
 
-        # execute setup callback
-        if info.setup is not None:
-            info.setup(utility)
+def setupUtility(site, utility, provides, name=u'',
+                 name_in_container=None, public=False, setup=None):
+    """Set up a utility in a site.
 
-        # register utility
-        site_manager.registerUtility(utility, provided=info.provides,
-                                     name=info.name)
+    site - the site to set up the utility in
+    utility - the utility to set up
+    provides - the interface the utility should be registered with
+    name - the name the utility should be registered under, default
+      the empty string (no name)
+    name_in_container - if given it will be used to add the utility
+      object to its container. Otherwise a name will be made up
+    public - if False, the utility will be stored in the site manager. If
+      True, the utility will be storedin the site (it is assumed the
+      site is a container)
+    setup - if not None, it will be called with the utility as its first
+       argument. This function can then be used to further set up the
+       utility.
+    """
+    site_manager = site.getSiteManager()
 
-    # we are done. If this subscriber gets fired again, we therefore
-    # do not register utilities anymore
-    site.__grok_utilities_installed__ = True
+    if not public:
+        container = site_manager
+    else:
+        container = site
 
+    if name_in_container is None:
+        name_in_container = INameChooser(container).chooseName(
+            utility.__class__.__name__, utility)
+    container[name_in_container] = utility
 
+    if setup is not None:
+        setup(utility)
+        
+    site_manager.registerUtility(utility, provided=provides,
+                                 name=name)
+    
 class DefinePermissionGrokker(grok.ModuleGrokker):
 
     priority = 1500
@@ -470,3 +494,71 @@
                                       provides=grok.interfaces.IApplication,
                                       name='%s.%s' % (module_info.dotted_name,
                                                       name))
+class IndexesGrokker(grok.InstanceGrokker):
+    component_class = components.IndexesClass
+
+    def register(self, context, name, factory, module_info, templates):
+        site = util.class_annotation(factory, 'grok.site', None)
+        if site is None:
+            raise GrokError("No site specified for grok.Indexes "
+                            "subclass in module %r. "
+                            "Use grok.site() to specify." % module_info.getModule(),
+                            factory)
+        indexes = util.class_annotation(factory, 'grok.indexes', None)
+        if indexes is None:
+            return
+        context = util.determine_class_context(factory, context)
+        catalog_name = util.class_annotation(factory, 'grok.name', u'')
+        zope.component.provideHandler(
+            IndexesSetupSubscriber(catalog_name, indexes,
+                                   context, module_info),
+            adapts=(site,
+                    grok.IObjectAddedEvent))
+        
+class IndexesSetupSubscriber(object):
+    def __init__(self, catalog_name, indexes, context, module_info):
+        self.catalog_name = catalog_name
+        self.indexes = indexes
+        self.context = context
+        self.module_info = module_info
+        
+    def __call__(self, site, event):
+        # make sure we have an intids
+        self._createIntIds(site)
+        # get the catalog
+        catalog = self._createCatalog(site)
+        # now install indexes
+        for name, index in self.indexes.items():
+            try:
+                index.setup(catalog, name, self.context, self.module_info)
+            except DuplicationError:
+                raise GrokError(
+                    "grok.Indexes in module %r causes "
+                    "creation of catalog index %r in catalog %r, "
+                    "but an index with that name is already present." %
+                    (self.module_info.getModule(), name, self.catalog_name),
+                    None)
+
+    def _createCatalog(self, site):
+        """Create the catalog if needed and return it.
+
+        If the catalog already exists, return that.
+        """
+        catalog = zope.component.queryUtility(
+            ICatalog, name=self.catalog_name, context=site, default=None)
+        if catalog is not None:
+            return catalog
+        catalog = Catalog()
+        setupUtility(site, catalog, ICatalog, name=self.catalog_name)
+        return catalog
+    
+    def _createIntIds(self, site):
+        """Create intids if needed, and return it.
+        """
+        intids = zope.component.queryUtility(
+            IIntIds, context=site, default=None)
+        if intids is not None:
+            return intids
+        intids = IntIds()
+        setupUtility(site, intids, IIntIds)
+        return intids



More information about the Checkins mailing list