[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