[Checkins] SVN: grokcore.site/trunk/ Added application from Grok. Changed the tests and imports.

Souheil Chelfouh cvs-admin at zope.org
Sat Apr 28 12:49:41 UTC 2012


Log message for revision 125360:
  Added application from Grok. Changed the tests and imports.
  Removed the use of WrongType.
  

Changed:
  U   grokcore.site/trunk/CHANGES.txt
  U   grokcore.site/trunk/setup.py
  U   grokcore.site/trunk/src/grokcore/site/__init__.py
  U   grokcore.site/trunk/src/grokcore/site/components.py
  A   grokcore.site/trunk/src/grokcore/site/ftests/application/
  A   grokcore.site/trunk/src/grokcore/site/ftests/application/__init__.py
  A   grokcore.site/trunk/src/grokcore/site/ftests/application/application.py
  U   grokcore.site/trunk/src/grokcore/site/ftests/test_grok_functional.py
  U   grokcore.site/trunk/src/grokcore/site/interfaces.py
  U   grokcore.site/trunk/src/grokcore/site/meta.py
  A   grokcore.site/trunk/src/grokcore/site/tests/application/
  A   grokcore.site/trunk/src/grokcore/site/tests/application/__init__.py
  A   grokcore.site/trunk/src/grokcore/site/tests/application/application.py
  U   grokcore.site/trunk/src/grokcore/site/tests/test_grok.py
  U   grokcore.site/trunk/src/grokcore/site/util.py

-=-
Modified: grokcore.site/trunk/CHANGES.txt
===================================================================
--- grokcore.site/trunk/CHANGES.txt	2012-04-28 11:00:32 UTC (rev 125359)
+++ grokcore.site/trunk/CHANGES.txt	2012-04-28 12:49:37 UTC (rev 125360)
@@ -4,7 +4,7 @@
 1.6 (unreleased)
 ----------------
 
-- Nothing changed yet.
+- Moved the directive `site` from Grok to this package.
 
 
 1.5 (2011-01-03)

Modified: grokcore.site/trunk/setup.py
===================================================================
--- grokcore.site/trunk/setup.py	2012-04-28 11:00:32 UTC (rev 125359)
+++ grokcore.site/trunk/setup.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -16,6 +16,7 @@
     'zope.configuration',
     'zope.location',
     'zope.testing',
+    'grokcore.content',
     ]
 
 setup(
@@ -42,6 +43,7 @@
     zip_safe=False,
     install_requires=['setuptools',
                       'ZODB3',
+                      'zope.event',
                       'grokcore.component >= 2.1',
                       'martian >= 0.13',
                       'zope.annotation',

Modified: grokcore.site/trunk/src/grokcore/site/__init__.py
===================================================================
--- grokcore.site/trunk/src/grokcore/site/__init__.py	2012-04-28 11:00:32 UTC (rev 125359)
+++ grokcore.site/trunk/src/grokcore/site/__init__.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -15,7 +15,7 @@
 
 from grokcore.component import *
 from grokcore.site.directive import site, local_utility
-from grokcore.site.components import Site, LocalUtility
+from grokcore.site.components import Site, LocalUtility, Application
 from grokcore.site.util import getApplication
 
 import grokcore.site.testing

Modified: grokcore.site/trunk/src/grokcore/site/components.py
===================================================================
--- grokcore.site/trunk/src/grokcore/site/components.py	2012-04-28 11:00:32 UTC (rev 125359)
+++ grokcore.site/trunk/src/grokcore/site/components.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -12,14 +12,13 @@
 #
 ##############################################################################
 
+from persistent import Persistent
 from grokcore.component.interfaces import IContext
-
-from persistent import Persistent
-
+from grokcore.site.interfaces import IApplication
+from zope.annotation.interfaces import IAttributeAnnotatable
+from zope.container.contained import Contained
 from zope.interface import implements
-from zope.annotation.interfaces import IAttributeAnnotatable
 from zope.site.site import SiteManagerContainer
-from zope.container.contained import Contained
 
 
 class BaseSite(object):
@@ -39,8 +38,22 @@
     Architecture entities like :class:`grokcore.site.LocalUtility` and
     :class:`grok.Indexes` objects; see those classes for more
     information.
+    """
 
+
+class Application(Site):
+    """Mixin for creating Grok application objects.
+
+    When a :class:`grokcore.content.Container` (or a
+    :class:`grokcore.content.Model`, though most developers
+    use containers) also inherits from :class:`grokcore.site.Application`,
+    it not only gains the component registration abilities of a
+    :class:`grokcore.site.site`, but will also be listed in the
+    Grok admin control panel as one of the applications
+    that the admin can install directly at the root of their Zope
+    database.
     """
+    implements(IApplication)
 
 
 class LocalUtility(Contained, Persistent):
@@ -62,6 +75,5 @@
     is one that the `grok.LocalUtility` already implements, in which
     case Grok cannot tell them apart, and `grok.provides()` must be
     used explicitly anyway).
-
     """
     implements(IContext, IAttributeAnnotatable)

Added: grokcore.site/trunk/src/grokcore/site/ftests/application/__init__.py
===================================================================
--- grokcore.site/trunk/src/grokcore/site/ftests/application/__init__.py	                        (rev 0)
+++ grokcore.site/trunk/src/grokcore/site/ftests/application/__init__.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.site/trunk/src/grokcore/site/ftests/application/application.py
===================================================================
--- grokcore.site/trunk/src/grokcore/site/ftests/application/application.py	                        (rev 0)
+++ grokcore.site/trunk/src/grokcore/site/ftests/application/application.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -0,0 +1,52 @@
+"""
+An application is a mixin for grok application objects.
+
+You can get the current application by using the
+grok.getApplication() function. Typically this will return the same
+object as grok.getSite(), but it is possible to have sub-Site objects
+which will be returned for grok.getSite(), where-as grok.getApplication
+will walk up the tree until it reaches the top-level site object.
+
+Let's create an application, then get it using grok.getApplication():
+
+  >>> import grokcore.site
+  >>> import zope.site.hooks
+  >>> root = getRootFolder()
+  >>> app = grokcore.site.util.create_application(Cave, root, 'mycave')
+  >>> root['cave'] = app
+  >>> zope.site.hooks.setSite(app)
+  >>> grokcore.site.getApplication()
+  <grokcore.site.ftests.application.application.Cave object at ...>
+
+Or get it using getSite():
+
+  >>> from zope.component.hooks import getSite
+  >>> getSite()
+  <grokcore.site.ftests.application.application.Cave object at ...>
+
+Now we can create a container with a sub-site. When we call grok.getSite()
+we'll get the box:
+
+  >>> root['cave']['box'] = WoodBox()
+  >>> zope.site.hooks.setSite(root['cave']['box'])
+  >>> getSite()
+  <grokcore.site.ftests.application.application.WoodBox object at ...>
+
+But when we call grokcore.site.util.getApplication() we get the cave:
+
+  >>> grokcore.site.getApplication()
+  <grokcore.site.ftests.application.application.Cave object at ...>
+
+"""
+import grokcore.content
+import grokcore.site
+
+
+class Cave(grokcore.content.Container, grokcore.site.Application):
+    """A shelter for homeless cavemen.
+    """
+
+
+class WoodBox(grokcore.content.Container, grokcore.site.Site):
+    """A prehistoric container for holding ZCA registries.
+    """

Modified: grokcore.site/trunk/src/grokcore/site/ftests/test_grok_functional.py
===================================================================
--- grokcore.site/trunk/src/grokcore/site/ftests/test_grok_functional.py	2012-04-28 11:00:32 UTC (rev 125359)
+++ grokcore.site/trunk/src/grokcore/site/ftests/test_grok_functional.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -32,7 +32,7 @@
 
 def test_suite():
     suite = unittest.TestSuite()
-    for name in ['utility', 'site']:
+    for name in ['utility', 'site', 'application']:
         suite.addTest(suiteFromPackage(name))
     return suite
 

Modified: grokcore.site/trunk/src/grokcore/site/interfaces.py
===================================================================
--- grokcore.site/trunk/src/grokcore/site/interfaces.py	2012-04-28 11:00:32 UTC (rev 125359)
+++ grokcore.site/trunk/src/grokcore/site/interfaces.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -12,10 +12,35 @@
 #
 ##############################################################################
 
-from zope.interface import Interface, Attribute
+from zope.interface import Interface, Attribute, implements
+from zope.component.interfaces import IObjectEvent
 from grokcore.component.interfaces import IGrokcoreComponentAPI
 
 
+class IApplication(Interface):
+    """Interface to mark the local site used as application root.
+    """
+
+
+class IApplicationInitializedEvent(IObjectEvent):
+    """A Grok Application has been created with success and is now ready
+    to be used.
+
+    This event can be used to trigger the creation of contents or other tasks
+    that require the application to be fully operational : utilities installed
+    and indexes created in the catalog."""
+
+
+class ApplicationInitializedEvent(object):
+    """A Grok Application has been created and is now ready to be used.
+    """
+    implements(IApplicationInitializedEvent)
+
+    def __init__(self, app):
+        assert IApplication.providedBy(app)
+        self.object = app
+
+
 class IUtilityInstaller(Interface):
     """This install an utility in a site. Let you have different
     'installation' method if you want (one for Zope2 / Zope3).
@@ -27,14 +52,10 @@
         """
 
 
-class IApplication(Interface):
-    """Interface to mark the local site used as application root.
-    """
-
-
 class IBaseClasses(Interface):
     Site = Attribute("Mixin class for sites.")
     LocalUtility = Attribute("Base class for local utilities.")
+    Application = Attribute("Base class for applications.")
 
 
 class IDirectives(Interface):

Modified: grokcore.site/trunk/src/grokcore/site/meta.py
===================================================================
--- grokcore.site/trunk/src/grokcore/site/meta.py	2012-04-28 11:00:32 UTC (rev 125359)
+++ grokcore.site/trunk/src/grokcore/site/meta.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -25,6 +25,7 @@
 import grokcore.site.components
 import grokcore.site.interfaces
 
+
 class SiteGrokker(martian.ClassGrokker):
     """Grokker for subclasses of `grokcore.site.Site`."""
     martian.component(grokcore.site.components.BaseSite)
@@ -110,5 +111,21 @@
     if setup is not None:
         setup(utility)
 
-    site_manager.registerUtility(utility, provided=provides,
-                                 name=name)
+    site_manager.registerUtility(utility, provided=provides, name=name)
+
+
+class ApplicationGrokker(martian.ClassGrokker):
+    """Grokker for Grok application classes."""
+    martian.component(grokcore.site.components.Application)
+    martian.priority(500)
+
+    def grok(self, name, factory, module_info, config, **kw):
+        # XXX fail loudly if the same application name is used twice.
+        provides = grokcore.site.interfaces.IApplication
+        name = '%s.%s' % (module_info.dotted_name, name)
+        config.action(
+            discriminator=('utility', provides, name),
+            callable=component.provideUtility,
+            args=(factory, provides, name),
+            )
+        return True

Added: grokcore.site/trunk/src/grokcore/site/tests/application/__init__.py
===================================================================
--- grokcore.site/trunk/src/grokcore/site/tests/application/__init__.py	                        (rev 0)
+++ grokcore.site/trunk/src/grokcore/site/tests/application/__init__.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.site/trunk/src/grokcore/site/tests/application/application.py
===================================================================
--- grokcore.site/trunk/src/grokcore/site/tests/application/application.py	                        (rev 0)
+++ grokcore.site/trunk/src/grokcore/site/tests/application/application.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -0,0 +1,37 @@
+"""
+
+After grokking a module that defines an application, the application factory is
+available as a utility::
+
+    >>> from grokcore.site import testing
+    >>> testing.grok(__name__)
+    
+    >>> import zope.component
+    >>> import grokcore.site.interfaces
+    >>> calendar_app = zope.component.getUtility(
+    ...     grokcore.site.interfaces.IApplication,
+    ...     name='grokcore.site.tests.application.application.Calendar')
+
+    >>> calendar_app
+    <class 'grokcore.site.tests.application.application.Calendar'>
+
+Applications are both containers and sites::
+
+    >>> issubclass(calendar_app, grokcore.site.Site)
+    True
+
+Applications can be instanciated without any arguments::
+
+    >>> calendar = calendar_app()
+    >>> calendar
+    <grokcore.site.tests.application.application.Calendar object at 0x...>
+
+"""
+
+import grokcore.site
+
+
+class Calendar(grokcore.site.Application):
+    """A calendar application that knows about ancient
+    calendar systems from the stone age.
+    """

Modified: grokcore.site/trunk/src/grokcore/site/tests/test_grok.py
===================================================================
--- grokcore.site/trunk/src/grokcore/site/tests/test_grok.py	2012-04-28 11:00:32 UTC (rev 125359)
+++ grokcore.site/trunk/src/grokcore/site/tests/test_grok.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -42,7 +42,7 @@
 
 def test_suite():
     suite = unittest.TestSuite()
-    for name in ['utility']:
+    for name in ['utility', 'application']:
         suite.addTest(suiteFromPackage(name))
     return suite
 

Modified: grokcore.site/trunk/src/grokcore/site/util.py
===================================================================
--- grokcore.site/trunk/src/grokcore/site/util.py	2012-04-28 11:00:32 UTC (rev 125359)
+++ grokcore.site/trunk/src/grokcore/site/util.py	2012-04-28 12:49:37 UTC (rev 125360)
@@ -12,12 +12,15 @@
 #
 ##############################################################################
 
-from grokcore.site.interfaces import IApplication
+import grokcore.site
+from grokcore.site.interfaces import IApplication, ApplicationInitializedEvent
 from zope.component.hooks import getSite
+from zope.event import notify
+from zope.lifecycleevent import ObjectCreatedEvent
 
 
 def getApplication():
-    """Return the nearest enclosing :class:`grok.Application`.
+    """Return the nearest enclosing :class:`grokcore.site.Application`.
 
     Raises :exc:`ValueError` if no application can be found.
     """
@@ -33,3 +36,29 @@
         obj = obj.__parent__
     raise ValueError("No application found.")
 
+
+def create_application(factory, container, name):
+    """Creates an application and triggers the events from
+    the application lifecycle.
+    """
+    # Check the factory.
+    assert IApplication.implementedBy(factory)
+
+    # Check the availability of the name in the container.
+    if name in container:
+        raise KeyError(name)
+
+    # Instanciate the application
+    application = factory()
+
+    # Trigger the creation event.
+    notify(ObjectCreatedEvent(application))
+
+    # Persist the application.
+    # This may raise a KeyError.
+    container[name] = application
+
+    # Trigger the initialization event.
+    notify(ApplicationInitializedEvent(application))
+
+    return application



More information about the checkins mailing list