[Checkins] SVN: grokcore.registries/ inital import

Christian Klinger cvs-admin at zope.org
Wed May 2 09:49:07 UTC 2012


Log message for revision 125599:
  inital import

Changed:
  A   grokcore.registries/
  A   grokcore.registries/trunk/
  A   grokcore.registries/trunk/.mr.developer.cfg
  A   grokcore.registries/trunk/CHANGES.txt
  A   grokcore.registries/trunk/LICENSE.txt
  A   grokcore.registries/trunk/README.txt
  A   grokcore.registries/trunk/bootstrap.py
  A   grokcore.registries/trunk/buildout.cfg
  A   grokcore.registries/trunk/setup.py
  A   grokcore.registries/trunk/src/
  A   grokcore.registries/trunk/src/grokcore/
  A   grokcore.registries/trunk/src/grokcore/__init__.py
  A   grokcore.registries/trunk/src/grokcore/registries/
  A   grokcore.registries/trunk/src/grokcore/registries/README.txt
  A   grokcore.registries/trunk/src/grokcore/registries/__init__.py
  A   grokcore.registries/trunk/src/grokcore/registries/components.py
  A   grokcore.registries/trunk/src/grokcore/registries/configure.zcml
  A   grokcore.registries/trunk/src/grokcore/registries/ftesting.zcml
  A   grokcore.registries/trunk/src/grokcore/registries/ftests/
  A   grokcore.registries/trunk/src/grokcore/registries/ftests/__init__.py
  A   grokcore.registries/trunk/src/grokcore/registries/ftests/registries/
  A   grokcore.registries/trunk/src/grokcore/registries/ftests/registries/__init__.py
  A   grokcore.registries/trunk/src/grokcore/registries/ftests/registries/basic.py
  A   grokcore.registries/trunk/src/grokcore/registries/ftests/registries/creation.py
  A   grokcore.registries/trunk/src/grokcore/registries/ftests/registries/grok_integration.py
  A   grokcore.registries/trunk/src/grokcore/registries/ftests/registries/utils.py
  A   grokcore.registries/trunk/src/grokcore/registries/ftests/test_grok_functional.py
  A   grokcore.registries/trunk/src/grokcore/registries/interfaces.py
  A   grokcore.registries/trunk/src/grokcore/registries/meta.py
  A   grokcore.registries/trunk/src/grokcore/registries/meta.zcml
  A   grokcore.registries/trunk/src/grokcore/registries/tests/
  A   grokcore.registries/trunk/src/grokcore/registries/tests/__init__.py
  A   grokcore.registries/trunk/src/grokcore/registries/tests/registries/
  A   grokcore.registries/trunk/src/grokcore/registries/tests/registries/__init__.py
  A   grokcore.registries/trunk/src/grokcore/registries/tests/registries/base.py
  A   grokcore.registries/trunk/src/grokcore/registries/tests/registries/global.py
  A   grokcore.registries/trunk/src/grokcore/registries/tests/registries/interfaces.py
  A   grokcore.registries/trunk/src/grokcore/registries/tests/registries/local.py
  A   grokcore.registries/trunk/src/grokcore/registries/tests/test_doc.py
  A   grokcore.registries/trunk/src/grokcore/registries/utils.py
  A   grokcore.registries/trunk/src/grokcore.component/
  A   grokcore.registries/trunk/src/grokcore.component/CHANGES.txt
  A   grokcore.registries/trunk/src/grokcore.component/COPYRIGHT.txt
  A   grokcore.registries/trunk/src/grokcore.component/CREDITS.txt
  A   grokcore.registries/trunk/src/grokcore.component/INSTALL.txt
  A   grokcore.registries/trunk/src/grokcore.component/LICENSE.txt
  A   grokcore.registries/trunk/src/grokcore.component/README.txt
  A   grokcore.registries/trunk/src/grokcore.component/TODO.txt
  A   grokcore.registries/trunk/src/grokcore.component/bootstrap.py
  A   grokcore.registries/trunk/src/grokcore.component/buildout.cfg
  A   grokcore.registries/trunk/src/grokcore.component/setup.py
  A   grokcore.registries/trunk/src/grokcore.component/src/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/components.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/decorators.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/directive.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/interfaces.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.zcml
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/subscription.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/testing.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/util.py
  A   grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/zcml.py
  A   grokcore.registries/trunk/src/grokcore.site/
  A   grokcore.registries/trunk/src/grokcore.site/CHANGES.txt
  A   grokcore.registries/trunk/src/grokcore.site/COPYRIGHT.txt
  A   grokcore.registries/trunk/src/grokcore.site/LICENSE.txt
  A   grokcore.registries/trunk/src/grokcore.site/README.txt
  A   grokcore.registries/trunk/src/grokcore.site/bootstrap.py
  A   grokcore.registries/trunk/src/grokcore.site/buildout.cfg
  A   grokcore.registries/trunk/src/grokcore.site/setup.py
  A   grokcore.registries/trunk/src/grokcore.site/src/
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/__init__.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/__init__.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/components.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/configure.zcml
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/directive.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftesting.zcml
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/__init__.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/__init__.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/application.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/__init__.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/site.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/test_grok_functional.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/__init__.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local_override.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/public.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/subclass.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/interfaces.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.zcml
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/subscriber.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/testing.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/__init__.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/__init__.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/application.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/test_grok.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/__init__.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany_fixture.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2_fixture.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone_fixture.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class_fixture.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive_fixture.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/publicnoncontainer.py
  A   grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/util.py

-=-
Added: grokcore.registries/trunk/.mr.developer.cfg
===================================================================
--- grokcore.registries/trunk/.mr.developer.cfg	                        (rev 0)
+++ grokcore.registries/trunk/.mr.developer.cfg	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,10 @@
+[buildout]
+args = 'bin/buildout'
+
+[develop]
+grokcore.site = true
+grokcore.component = true
+
+[mr.developer]
+rewrites = 
+

Added: grokcore.registries/trunk/CHANGES.txt
===================================================================
--- grokcore.registries/trunk/CHANGES.txt	                        (rev 0)
+++ grokcore.registries/trunk/CHANGES.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,21 @@
+=======
+Changes
+=======
+
+1.2 (unreleased)
+================
+
+- Nothing changed yet.
+
+
+1.1 (2011-01-20)
+================
+
+- Use zope.errorview for the functional tests. This lifts the dependency on
+  zope.app.http.
+
+1.0 (2011-01-03)
+================
+
+- Factor out form grok base package
+

Added: grokcore.registries/trunk/LICENSE.txt
===================================================================
--- grokcore.registries/trunk/LICENSE.txt	                        (rev 0)
+++ grokcore.registries/trunk/LICENSE.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,44 @@
+Zope Public License (ZPL) Version 2.1
+
+A copyright notice accompanies this license document that identifies the
+copyright holders.
+
+This license has been certified as open source. It has also been designated as
+GPL compatible by the Free Software Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions in source code must retain the accompanying copyright
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying copyright
+notice, this list of conditions, and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to endorse or promote
+products derived from this software without prior written permission from the
+copyright holders.
+
+4. The right to distribute this software or to use it for any purpose does not
+give you the right to use Servicemarks (sm) or Trademarks (tm) of the
+copyright
+holders. Use of them is covered by separate agreement with the copyright
+holders.
+
+5. If any files are modified, you must cause the modified files to carry
+prominent notices stating that you changed the files and the date of any
+change.
+
+Disclaimer
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: grokcore.registries/trunk/README.txt
===================================================================
--- grokcore.registries/trunk/README.txt	                        (rev 0)
+++ grokcore.registries/trunk/README.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+===============
+grokcore.xmlrpc
+===============
+
+XML-RPC Views for Grok.
+
+This package provides base classes for XML-RPC Views for Grok.

Added: grokcore.registries/trunk/bootstrap.py
===================================================================
--- grokcore.registries/trunk/bootstrap.py	                        (rev 0)
+++ grokcore.registries/trunk/bootstrap.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,260 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
+from optparse import OptionParser
+
+if sys.platform == 'win32':
+    def quote(c):
+        if ' ' in c:
+            return '"%s"' % c # work around spawn lamosity on windows
+        else:
+            return c
+else:
+    quote = str
+
+# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
+stdout, stderr = subprocess.Popen(
+    [sys.executable, '-Sc',
+     'try:\n'
+     '    import ConfigParser\n'
+     'except ImportError:\n'
+     '    print 1\n'
+     'else:\n'
+     '    print 0\n'],
+    stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+has_broken_dash_S = bool(int(stdout.strip()))
+
+# In order to be more robust in the face of system Pythons, we want to
+# run without site-packages loaded.  This is somewhat tricky, in
+# particular because Python 2.6's distutils imports site, so starting
+# with the -S flag is not sufficient.  However, we'll start with that:
+if not has_broken_dash_S and 'site' in sys.modules:
+    # We will restart with python -S.
+    args = sys.argv[:]
+    args[0:0] = [sys.executable, '-S']
+    args = map(quote, args)
+    os.execv(sys.executable, args)
+# Now we are running with -S.  We'll get the clean sys.path, import site
+# because distutils will do it later, and then reset the path and clean
+# out any namespace packages from site-packages that might have been
+# loaded by .pth files.
+clean_path = sys.path[:]
+import site
+sys.path[:] = clean_path
+for k, v in sys.modules.items():
+    if k in ('setuptools', 'pkg_resources') or (
+        hasattr(v, '__path__') and
+        len(v.__path__)==1 and
+        not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
+        # This is a namespace package.  Remove it.
+        sys.modules.pop(k)
+
+is_jython = sys.platform.startswith('java')
+
+setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
+distribute_source = 'http://python-distribute.org/distribute_setup.py'
+
+# parsing arguments
+def normalize_to_url(option, opt_str, value, parser):
+    if value:
+        if '://' not in value: # It doesn't smell like a URL.
+            value = 'file://%s' % (
+                urllib.pathname2url(
+                    os.path.abspath(os.path.expanduser(value))),)
+        if opt_str == '--download-base' and not value.endswith('/'):
+            # Download base needs a trailing slash to make the world happy.
+            value += '/'
+    else:
+        value = None
+    name = opt_str[2:].replace('-', '_')
+    setattr(parser.values, name, value)
+
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
+
+Bootstraps a buildout-based project.
+
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", dest="version",
+                          help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+                   action="store_true", dest="use_distribute", default=False,
+                   help="Use Distribute rather than Setuptools.")
+parser.add_option("--setup-source", action="callback", dest="setup_source",
+                  callback=normalize_to_url, nargs=1, type="string",
+                  help=("Specify a URL or file location for the setup file. "
+                        "If you use Setuptools, this will default to " +
+                        setuptools_source + "; if you use Distribute, this "
+                        "will default to " + distribute_source +"."))
+parser.add_option("--download-base", action="callback", dest="download_base",
+                  callback=normalize_to_url, nargs=1, type="string",
+                  help=("Specify a URL or directory for downloading "
+                        "zc.buildout and either Setuptools or Distribute. "
+                        "Defaults to PyPI."))
+parser.add_option("--eggs",
+                  help=("Specify a directory for storing eggs.  Defaults to "
+                        "a temporary directory that is deleted when the "
+                        "bootstrap script completes."))
+parser.add_option("-t", "--accept-buildout-test-releases",
+                  dest='accept_buildout_test_releases',
+                  action="store_true", default=False,
+                  help=("Normally, if you do not specify a --version, the "
+                        "bootstrap script and buildout gets the newest "
+                        "*final* versions of zc.buildout and its recipes and "
+                        "extensions for you.  If you use this flag, "
+                        "bootstrap and buildout will get the newest releases "
+                        "even if they are alphas or betas."))
+parser.add_option("-c", None, action="store", dest="config_file",
+                   help=("Specify the path to the buildout configuration "
+                         "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout's main function
+if options.config_file is not None:
+    args += ['-c', options.config_file]
+
+if options.eggs:
+    eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
+else:
+    eggs_dir = tempfile.mkdtemp()
+
+if options.setup_source is None:
+    if options.use_distribute:
+        options.setup_source = distribute_source
+    else:
+        options.setup_source = setuptools_source
+
+if options.accept_buildout_test_releases:
+    args.append('buildout:accept-buildout-test-releases=true')
+args.append('bootstrap')
+
+try:
+    import pkg_resources
+    import setuptools # A flag.  Sometimes pkg_resources is installed alone.
+    if not hasattr(pkg_resources, '_distribute'):
+        raise ImportError
+except ImportError:
+    ez_code = urllib2.urlopen(
+        options.setup_source).read().replace('\r\n', '\n')
+    ez = {}
+    exec ez_code in ez
+    setup_args = dict(to_dir=eggs_dir, download_delay=0)
+    if options.download_base:
+        setup_args['download_base'] = options.download_base
+    if options.use_distribute:
+        setup_args['no_fake'] = True
+    ez['use_setuptools'](**setup_args)
+    if 'pkg_resources' in sys.modules:
+        reload(sys.modules['pkg_resources'])
+    import pkg_resources
+    # This does not (always?) update the default working set.  We will
+    # do it.
+    for path in sys.path:
+        if path not in pkg_resources.working_set.entries:
+            pkg_resources.working_set.add_entry(path)
+
+cmd = [quote(sys.executable),
+       '-c',
+       quote('from setuptools.command.easy_install import main; main()'),
+       '-mqNxd',
+       quote(eggs_dir)]
+
+if not has_broken_dash_S:
+    cmd.insert(1, '-S')
+
+find_links = options.download_base
+if not find_links:
+    find_links = os.environ.get('bootstrap-testing-find-links')
+if find_links:
+    cmd.extend(['-f', quote(find_links)])
+
+if options.use_distribute:
+    setup_requirement = 'distribute'
+else:
+    setup_requirement = 'setuptools'
+ws = pkg_resources.working_set
+setup_requirement_path = ws.find(
+    pkg_resources.Requirement.parse(setup_requirement)).location
+env = dict(
+    os.environ,
+    PYTHONPATH=setup_requirement_path)
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+    # Figure out the most recent final version of zc.buildout.
+    import setuptools.package_index
+    _final_parts = '*final-', '*final'
+    def _final_version(parsed_version):
+        for part in parsed_version:
+            if (part[:1] == '*') and (part not in _final_parts):
+                return False
+        return True
+    index = setuptools.package_index.PackageIndex(
+        search_path=[setup_requirement_path])
+    if find_links:
+        index.add_find_links((find_links,))
+    req = pkg_resources.Requirement.parse(requirement)
+    if index.obtain(req) is not None:
+        best = []
+        bestv = None
+        for dist in index[req.project_name]:
+            distv = dist.parsed_version
+            if _final_version(distv):
+                if bestv is None or distv > bestv:
+                    best = [dist]
+                    bestv = distv
+                elif distv == bestv:
+                    best.append(dist)
+        if best:
+            best.sort()
+            version = best[-1].version
+if version:
+    requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+if is_jython:
+    import subprocess
+    exitcode = subprocess.Popen(cmd, env=env).wait()
+else: # Windows prefers this, apparently; otherwise we would prefer subprocess
+    exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
+if exitcode != 0:
+    sys.stdout.flush()
+    sys.stderr.flush()
+    print ("An error occurred when trying to install zc.buildout. "
+           "Look above this message for any errors that "
+           "were output by easy_install.")
+    sys.exit(exitcode)
+
+ws.add_entry(eggs_dir)
+ws.require(requirement)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+if not options.eggs: # clean up temporary egg directory
+    shutil.rmtree(eggs_dir)

Added: grokcore.registries/trunk/buildout.cfg
===================================================================
--- grokcore.registries/trunk/buildout.cfg	                        (rev 0)
+++ grokcore.registries/trunk/buildout.cfg	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+[buildout]
+extends = http://svn.zope.org/repos/main/groktoolkit/trunk/grok.cfg
+develop = .
+parts =
+  test
+  omelette
+extensions =
+  buildout.dumppickedversions
+  mr.developer
+
+[versions]
+grokcore.registries =
+grokcore.component =
+
+[omelette]
+recipe = collective.recipe.omelette
+eggs = ${test:eggs}
+
+[test]
+recipe = zc.recipe.testrunner
+eggs =
+    grokcore.registries
+    grokcore.registries [test]
+defaults = ['--tests-pattern', '^f?tests$', '-v', '--auto-color']

Added: grokcore.registries/trunk/setup.py
===================================================================
--- grokcore.registries/trunk/setup.py	                        (rev 0)
+++ grokcore.registries/trunk/setup.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,57 @@
+from setuptools import setup, find_packages
+import os
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+long_description = (
+    read('README.txt')
+    + '\n' +
+    read('CHANGES.txt')
+    + '\n' +
+    'Download\n'
+    '********\n'
+    )
+
+tests_require = [
+    'zope.app.appsetup',
+    'zope.app.wsgi',
+    'zope.app.testing',
+    'grokcore.component',
+    'grokcore.site',
+    'zope.testing',
+    ]
+
+setup(
+    name='grokcore.registries',
+    version='0.1',
+    author='Grok Team',
+    author_email='grok-dev at zope.org',
+    url='http://grok.zope.org',
+    download_url='http://cheeseshop.python.org/pypi/grokcore.json/',
+    description='Advanced Registry Behavior for Grok.',
+    long_description=long_description,
+    license='ZPL',
+    classifiers=[
+        'Environment :: Web Environment',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: Zope Public License',
+        'Programming Language :: Python',
+        'Framework :: Zope3',
+        ],
+    packages=find_packages('src'),
+    package_dir = {'': 'src'},
+    namespace_packages=['grokcore'],
+    include_package_data = True,
+    zip_safe=False,
+    install_requires=[
+        'setuptools',
+        'zope.component',
+        'zope.configuration',
+        'zope.interface',
+        'zope.location',
+        'zope.schema',
+        ],
+    tests_require=tests_require,
+    extras_require={'test': tests_require},
+)

Added: grokcore.registries/trunk/src/grokcore/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)

Added: grokcore.registries/trunk/src/grokcore/registries/README.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/README.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/README.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,145 @@
+===================
+grokcore.registries
+===================
+
+With the help of this package you are now able to create
+your on BaseComponents Registries. With the help of
+a zcml directive ´registerIn´ you can choose in which
+Registry your grok Components will be registerd.
+
+Setup
+-----
+
+The first thing we have to do is to create an instance of
+a BaseComponents Regsitry. For this task we use the
+create_components_registry.
+
+  >>> from grokcore.registries import create_components_registry
+  >>> from zope.component.interfaces import IComponents
+  >>> import zope.component
+
+  >>> myRegistry = create_components_registry(name="myRegistry")
+
+  >>> myRegistry
+  <BaseComponents myRegistry>
+
+  >>> IComponents.providedBy(myRegistry)
+  True
+
+
+It's possible to create a chain of Registries you have to provide
+your Bases in the third argument of the create_components_registry.
+
+  >>> myOtherRegistry = create_components_registry(
+  ...     zope.component.globalSiteManager, 'myRegistry', (myRegistry,))
+  >>> myOtherRegistry.__bases__
+  (<BaseComponents myRegistry>,)
+
+
+Basic Working
+-------------
+
+  >>> custom = create_components_registry(
+  ...     zope.component.globalSiteManager, 'custom')
+
+Let's make sure that the parent of the custom registry is the base registry:
+
+  >>> custom.__parent__
+  <BaseGlobalComponents base>
+
+We make the custom Registry a Utility:
+
+  >>> from zope.component.interfaces import IComponents
+  >>> zope.component.provideUtility(custom, IComponents, 'custom')
+
+  >>> custom = zope.component.getUtility(IComponents, name='custom')
+  >>> custom
+  <BaseComponents custom>
+
+
+Now the registerIn function comes into the game. We register all stuff
+from ´registries.global´ to the GlobalSiteManager, and the contents of
+´registries.local´ to our custom Registry.
+  >>> from zope.configuration import xmlconfig
+
+
+ >>> context = xmlconfig.string('''
+ ... <configure i18n_domain="zope">
+ ...   <include package="zope.component" file="meta.zcml" />
+ ...   <include package="grokcore.registries" file="meta.zcml" />
+ ...   <include package="grokcore.site" />
+ ... </configure>
+ ... ''')
+
+  >>> context = xmlconfig.string('''
+  ... <configure xmlns="http://namespaces.zope.org/zope"
+  ...            xmlns:grok="http://namespaces.zope.org/grok"
+  ...            i18n_domain="zope">
+  ...
+  ...   <include package="grokcore.component" file="meta.zcml" />
+  ...
+  ...   <grok:grok package="grokcore.registries.tests.registries.global" />
+  ...   <registerIn registry="README.custom">
+  ...     <grok:grok package="grokcore.registries.tests.registries.local" />
+  ...   </registerIn>
+  ...
+  ... </configure>
+  ... ''', context=context)
+
+Now we can verify if we found our Components in the valid registries.
+We start in searching in the GlobalSiteManager:
+
+
+  >>> from grokcore.registries.tests.registries.interfaces import IExample
+  >>> zope.component.getUtility(IExample, name="global")
+  <grokcore.registries.tests.registries.global.MyExample object at ...>
+
+  >>> zope.component.getUtility(IExample, name="local")
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: (<InterfaceClass grokcore.registries.tests.registries.interfaces.IExample>, 'local')
+
+
+Now we use our ´custom´ one:
+
+  >>> custom.getUtility(IExample, name="global")
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: (<InterfaceClass grokcore.registries.tests.registries.interfaces.IExample>, 'global')
+
+  >>> custom.getUtility(IExample, name="local")
+  <grokcore.registries.tests.registries.local.MyExample object at ...>
+
+
+Using BaseRegistries (Stacked Registries)
+-----------------------------------------
+
+  >>> from grokcore.site import Application
+  >>> site = Application()
+  >>> from zope.site.site import LocalSiteManager
+  >>> site.setSiteManager(LocalSiteManager(site))
+  >>> sm = site.getSiteManager()
+
+  >>> sm.__bases__
+  (<BaseGlobalComponents base>,)
+
+
+  >>> sm.getUtility(IExample, name="global")
+  <grokcore.registries.tests.registries.global.MyExample object at 0...>
+
+  >>> sm.getUtility(IExample, name="local")
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: (<InterfaceClass grokcore.registries.tests.registries.interfaces.IExample>, 'local')
+
+If we stack our "custom" registry, in to the GlobalSiteManager we found all registries 
+
+  >>> sm.__bases__ += (custom,)
+  >>> sm.__bases__
+  (<BaseGlobalComponents base>, <BaseComponents custom>)
+
+  >>> sm.getUtility(IExample, name="global")
+  <grokcore.registries.tests.registries.global.MyExample object at 0...>
+
+  >>> sm.getUtility(IExample, name="local")
+  <grokcore.registries.tests.registries.local.MyExample object at 0...>

Added: grokcore.registries/trunk/src/grokcore/registries/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from grokcore.registries.components import BaseComponents
+from grokcore.registries.components import create_components_registry 

Added: grokcore.registries/trunk/src/grokcore/registries/components.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/components.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/components.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,60 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Base classes for Grok application components.
+
+When an application developer builds a Grok-based application, the
+classes they define each typically inherit from one of the base classes
+provided here.
+
+"""
+
+from grokcore.registries.utils import query_registry, contextualSiteManager
+from zope.component.globalregistry import GlobalAdapterRegistry
+from zope.interface import implements, directlyProvides
+from zope.component.interfaces import IComponents, IComponentLookup
+from zope.component.registry import Components
+from zope.location import Location
+
+
+registries = {}
+
+
+class BaseComponents(Location, Components):
+    implements(IComponentLookup)
+
+    def __init__(self, parent, name, bases=()):
+        self.__name__ = name
+        self.__parent__ = parent
+        self._init_registries()
+        self._init_registrations()
+        self.__bases__ = tuple(bases)
+
+    def _init_registries(self):
+        self.adapters = GlobalAdapterRegistry(self, 'adapters')
+        self.utilities = GlobalAdapterRegistry(self, 'utilities')
+
+    def __reduce__(self):
+        # Global site managers are pickled as global objects
+        return query_registry, (self.__name__, self.__parent__)
+
+
+def create_components_registry(parent=None, name='', bases=()):
+    if parent is None:
+        parent = contextualSiteManager()
+    registry = BaseComponents(parent, name, bases)
+    directlyProvides(registry, IComponents)
+    if name in registries.keys():
+        RuntimeError('Duplicated key for registry %r found.' % name)
+    registries[name] = registry
+    return registry
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore/registries/configure.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/configure.zcml	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/configure.zcml	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+<configure
+  xmlns="http://namespaces.zope.org/zope"
+  xmlns:browser="http://namespaces.zope.org/browser"
+  xmlns:grok="http://namespaces.zope.org/grok">
+
+  <include package="grokcore.site" />
+  <include package="." file="meta.zcml" />
+
+</configure>

Added: grokcore.registries/trunk/src/grokcore/registries/ftesting.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftesting.zcml	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftesting.zcml	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,22 @@
+<configure
+   xmlns="http://namespaces.zope.org/zope"
+   xmlns:grok="http://namespaces.zope.org/grok"
+   xmlns:browser="http://namespaces.zope.org/browser"
+   i18n_domain="grokcore.registries"
+   package="grokcore.registries">
+
+  <include package="zope.app.appsetup" file="ftesting.zcml" />
+
+  <include package="grokcore.registries" file="meta.zcml" />
+  <include package="grokcore.registries" />
+
+  <grok:grok package="grokcore.registries.ftests" />
+
+  <grok:grok package="grokcore.registries.tests.registries.global" />
+  <registerIn registry="grokcore.registries.ftests.registries.basic.specialRegistry">
+      <grok:grok package="grokcore.registries.tests.registries.local" />
+  </registerIn>
+
+
+</configure>
+

Added: grokcore.registries/trunk/src/grokcore/registries/ftests/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# package

Added: grokcore.registries/trunk/src/grokcore/registries/ftests/registries/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/registries/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/registries/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# package

Added: grokcore.registries/trunk/src/grokcore/registries/ftests/registries/basic.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/registries/basic.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/registries/basic.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,20 @@
+"""
+ >>> from zope.component import getUtility
+ >>> from grokcore.registries.tests.registries.interfaces import IExample
+
+ >>> getUtility(IExample, name=u'global')
+ <grokcore.registries.tests.registries.global.MyExample object at ...>
+
+ >>> getUtility(IExample, name=u'local')
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.registries.tests.registries.interfaces.IExample>, u'local')
+
+ >>> specialRegistry.getUtility(IExample, name=u'local')
+ <grokcore.registries.tests.registries.local.MyExample object at ...>
+"""
+
+from grokcore.registries import create_components_registry
+
+
+specialRegistry = create_components_registry(name="specialRegistry")

Added: grokcore.registries/trunk/src/grokcore/registries/ftests/registries/creation.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/registries/creation.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/registries/creation.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+  >>> my_registry
+  <BaseComponents my_registry>
+
+  >>> from zope.component.interfaces import IComponents
+  >>> IComponents.providedBy(my_registry)
+  True
+
+  >>> chained_registry
+  <BaseComponents chained_registry>
+
+  >>> chained_registry.__bases__
+  (<BaseComponents my_registry>,)
+"""
+
+import zope.component
+from grokcore.registries import create_components_registry
+
+my_registry = create_components_registry(name="my_registry")
+
+chained_registry = create_components_registry(
+    zope.component.globalSiteManager,
+    'chained_registry',
+    (my_registry,),
+    )

Added: grokcore.registries/trunk/src/grokcore/registries/ftests/registries/grok_integration.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/registries/grok_integration.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/registries/grok_integration.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,41 @@
+"""
+ >>> root = getRootFolder()
+ >>> create_application(MyApplication, root, 'app')
+ <grokcore.registries.ftests.registries.grok_integration.MyApplication ...>
+
+ >>> from zope.component import getUtility
+ >>> from grokcore.registries.tests.registries.interfaces import IExample
+
+ >>> getUtility(IExample, name=u'global')
+ <grokcore.registries.tests.registries.global.MyExample object at ...>
+
+ >>> getUtility(IExample, name=u'local')
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.registries.tests.registries.interfaces.IExample>, u'local')
+
+ >>> specialRegistry.getUtility(IExample, name=u'local')
+ <grokcore.registries.tests.registries.local.MyExample object at ...>
+
+ >>> app = root['app']
+ >>> from zope.component.hooks import setSite
+ >>> setSite(root['app'])
+
+ >>> getUtility(IExample, name=u'local')
+ <grokcore.registries.tests.registries.local.MyExample object at ...>
+
+ >>> setSite()
+
+"""
+
+from grokcore.site import Application
+from grokcore.site.util import create_application
+from grokcore.registries.ftests.registries.basic import specialRegistry
+
+
+class MyApplication(Application):
+
+    def getSiteManager(self):
+        current = super(MyApplication, self).getSiteManager()
+        current.__bases__ += (specialRegistry,)
+        return current
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore/registries/ftests/registries/utils.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/registries/utils.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/registries/utils.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+"""
+  >>> from grokcore.registries.components import registries
+  >>> from pprint import pprint
+  >>> pprint(registries)
+  {'chained_registry': <BaseComponents chained_registry>,
+   'my_registry': <BaseComponents my_registry>,
+   'specialRegistry': <BaseComponents specialRegistry>}
+
+"""
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore/registries/ftests/test_grok_functional.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/test_grok_functional.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/test_grok_functional.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,41 @@
+import unittest
+import grokcore.registries
+
+from pkg_resources import resource_listdir
+from zope.testing import doctest
+from zope.app.appsetup.testlayer import ZODBLayer
+
+FunctionalLayer = ZODBLayer(grokcore.registries)
+
+
+def suiteFromPackage(name):
+    files = resource_listdir(__name__, name)
+    suite = unittest.TestSuite()
+    for filename in files:
+        if not filename.endswith('.py'):
+            continue
+        if filename == '__init__.py':
+            continue
+
+        dottedname = 'grokcore.registries.ftests.%s.%s' % (name, filename[:-3])
+        test = doctest.DocTestSuite(
+            dottedname,
+            extraglobs=dict(getRootFolder=FunctionalLayer.getRootFolder),
+            optionflags=(doctest.ELLIPSIS+
+                         doctest.NORMALIZE_WHITESPACE+
+                         doctest.REPORT_NDIFF)
+            )
+        test.layer = FunctionalLayer
+
+        suite.addTest(test)
+    return suite
+
+def test_suite():
+    suite = unittest.TestSuite()
+    for name in ['registries']:
+        suite.addTest(suiteFromPackage(name))
+    return suite
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
+

Added: grokcore.registries/trunk/src/grokcore/registries/interfaces.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/interfaces.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/interfaces.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,33 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok interfaces
+"""
+
+from zope.configuration.fields import GlobalObject
+from zope.interface import Interface
+from zope.schema import TextLine
+
+
+class IRegisterInDirective(Interface):
+    """Use the specified registry for registering the contained components.
+    """
+    name = TextLine(
+        title=u"Registration name",
+        description=u"Name under which the registry is or will be registered.",
+        required=False)
+
+    registry = GlobalObject(
+        title=u"Registry",
+        description=u"Python path to the registry to use.",
+        required=False)

Added: grokcore.registries/trunk/src/grokcore/registries/meta.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/meta.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/meta.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,95 @@
+#############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grokkers for Grok-configured components.
+
+This `meta` module contains the actual grokker mechanisms for which the
+Grok web framework is named.  A directive in the adjacent `meta.zcml`
+file directs the `martian` library to scan this file, where it discovers
+and registers the grokkers you see below.  The grokkers are then active
+and available as `martian` recursively examines the packages and modules
+of a Grok-based web application.
+
+"""
+import warnings
+from zope.component.hooks import setSite, getSite
+from grokcore.registries.components import query_registry
+from zope.configuration.config import GroupingContextDecorator
+from zope.configuration.exceptions import ConfigurationError
+
+
+class ConfigurationWrapperSite(object):
+    """This a minimal fake Site, the only responsibility it has
+    is to store our registry as a SiteManager and return it later.
+    This is needed to fool siteinfo via setSite, zope.component.zcml.handler
+    will grab the registry via zope.component.getSiteManager() then.
+    """
+    def __init__(self, sm):
+        self.sm = sm
+
+    def getSiteManager(self):
+        return self.sm
+
+
+def setActiveRegistry(context, registry):
+    context.original = getSite()
+    fakeSite = ConfigurationWrapperSite(registry)
+    setSite(fakeSite)
+
+
+def resetOriginalRegistry(context):
+    setSite(context.original)
+
+
+class RegisterIn(GroupingContextDecorator):
+
+    # Marker that this directive has been used in the path
+    registryChanged = True
+
+    # Storage for the original site
+    original = None
+
+    def __init__(self, context, name="", registry=None, **kw):
+        if not (bool(name) ^ bool(registry)):
+            raise ConfigurationError(
+                'You need to provide either the name of the registry or the '
+                'registry object for the ``registerIn`` directive.')
+
+        if hasattr(context, 'registryChanged') and context.registryChanged:
+            raise ConfigurationError(
+                'Nested ``registerIn`` directives are not permitted.')
+
+        super(RegisterIn, self).__init__(context, **kw)
+
+        if registry is None:
+            self.registry = query_registry(name)
+            if self.registry is None:
+                raise ConfigurationError(
+                    'No registry component given and no registry registered'
+                    ' under the name %r' % name)
+        else:
+            self.registry = registry
+
+    def before(self):
+        self.context.action(
+            discriminator=None,
+            callable=setActiveRegistry,
+            args=(self, self.registry),
+            )
+
+    def after(self):
+        self.context.action(
+            discriminator=None,
+            callable=resetOriginalRegistry,
+            args=(self,),
+            )
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore/registries/meta.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/meta.zcml	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/meta.zcml	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,11 @@
+<configure xmlns="http://namespaces.zope.org/meta">
+
+  <directives namespace="http://namespaces.zope.org/zope">
+    <groupingDirective
+        name="registerIn"
+        schema=".interfaces.IRegisterInDirective"
+        handler=".meta.RegisterIn"
+        />
+  </directives>
+
+</configure>

Added: grokcore.registries/trunk/src/grokcore/registries/tests/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# i am a package

Added: grokcore.registries/trunk/src/grokcore/registries/tests/registries/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/registries/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/registries/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+#package

Added: grokcore.registries/trunk/src/grokcore/registries/tests/registries/base.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/registries/base.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/registries/base.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+import grokcore.component as grok
+from grokcore.registries.tests.registries.interfaces import IExample
+
+
+class MyExample(grok.GlobalUtility):
+    grok.name('override')
+    grok.implements(IExample)

Added: grokcore.registries/trunk/src/grokcore/registries/tests/registries/global.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/registries/global.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/registries/global.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+import grokcore.component as grok
+
+
+from grokcore.registries.tests.registries.interfaces import IExample
+
+
+class MyExample(grok.GlobalUtility):
+    grok.name('global')
+    grok.implements(IExample)

Added: grokcore.registries/trunk/src/grokcore/registries/tests/registries/interfaces.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/registries/interfaces.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/registries/interfaces.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,5 @@
+from zope.interface import Interface
+
+
+class IExample(Interface):
+    pass
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore/registries/tests/registries/local.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/registries/local.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/registries/local.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+import grokcore.component as grok
+
+
+from grokcore.registries.tests.registries.interfaces import IExample
+
+
+class MyExample(grok.GlobalUtility):
+    grok.name('local')
+    grok.implements(IExample)
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore/registries/tests/test_doc.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/test_doc.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/test_doc.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,22 @@
+import doctest
+import unittest
+from zope.app.testing import placelesssetup, setup
+
+def setUp(test):
+    placelesssetup.setUp(test)
+    setup.setUpTestAsModule(test, name='README')
+
+def tearDown(test):
+    placelesssetup.tearDown(test)
+
+def test_suite():
+    return unittest.TestSuite((
+            doctest.DocFileSuite(
+                '../README.txt',
+                setUp=setUp, tearDown=tearDown,
+                optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                ),
+            ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')

Added: grokcore.registries/trunk/src/grokcore/registries/utils.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/utils.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/utils.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+
+import pkg_resources
+from zope.component import queryUtility, getSiteManager, getGlobalSiteManager
+from zope.component.interfaces import IComponents
+
+
+def contextualSiteManager():
+    return getSiteManager() or getGlobalSiteManager()
+
+
+def query_registry(name, parent_components=None):
+    if parent_components is None:
+        parent_components = contextualSiteManager()
+    return parent_components.getUtility(IComponents, name)

Added: grokcore.registries/trunk/src/grokcore.component/CHANGES.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/CHANGES.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/CHANGES.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,210 @@
+Changes
+=======
+
+2.5 (unreleased)
+----------------
+
+- Introduce provideUtility, providerAdapter, provideSubscriptionAdapter,
+  provideHandler and provideInterface in grokcore.component. These by default
+  delegate the registration of components to the global site manager like
+  was done before, but provide the possibility for custom registries for the
+  grokked components.
+
+- Fix the `global_adapter` to properly use information annotated by
+  ``grok.adapter``, and using the IContext object if it was not
+  specified. (Fix Launchpad issue #960097).
+
+- Add a ``key`` option to ``sort_components`` that behave like ``key``
+  options available on standard Python sort methods.
+
+2.4 (2011-04-27)
+----------------
+
+- Fix the `global_adapter` directive implementation to accept an explicit
+  "empty" name for nameless adapter registrations (as it used to be that
+  providing an empty name in the registration would actually result in
+  registering a named adapter in case the factory has a `grok.name`).
+
+2.3 (2011-02-14)
+----------------
+
+- Implement the generic (Multi)Subscriptions components.
+
+2.2 (2010-11-03)
+----------------
+
+- The default values computation for the context directive and the provides
+  directive is now defined in the directives themselves. This means that where
+  the values for these directives is being retrieved, the "default_context"
+  function does not need to be passed along anymore for general cases.
+
+  Analogous to this, when getting values for the provides directive the
+  "default_provides" function does not need to be passed along in the general
+  case.
+
+2.1 (2010-11-01)
+----------------
+
+* Made package comply to zope.org repository policy.
+
+* Moved directives 'order' from grokcore.viewlet and 'path' from
+  grokcore.view to this very package.
+
+* Tiny dependency adjustment: moved zope.event to test dependencies.
+
+* Port from 1.x branch exclude parameter to the Grok ZCML directive.
+
+* Port from 1.x branch the ignore of testing.py modules.
+
+2.0 (2009-09-16)
+----------------
+
+* Use a newer version of Martian that has better support for
+  inheritance.  This is demonstrated in ``tests/inherit``.
+
+* The ``ContextGrokker`` and the ``scan.py`` module have gone away
+  thanks the newer Martian.
+
+* Directive implementations (in their factory method) should *not*
+  bind directives. Directive binding cannot take place at import time,
+  but only at grok time. Binding directives during import time (when
+  directives are executed) can lead to change problems. (we noticed
+  this during our refactoring to use the new Martian).
+
+* Use 1.0b1 versions.cfg in Grok's release info instead of a local
+  copy; a local copy for all grokcore packages is just too hard to
+  maintain.
+
+1.7 (2009-06-01)
+----------------
+
+* Add missing provider, global_adapter, implementsOnly, classProvides() to
+  the module interface so that they are included in __all__
+
+1.6 (2009-04-10)
+----------------
+
+* Add convenience imports for implementsOnly() and classProvides() class
+  declarations form zope.interface.
+
+* Add support for registering global adapters at module level::
+
+    grok.global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
+
+  Only 'factory' is required. If only a single interface is adapted, the
+  second argument may be a single interface instead of a tuple. If the
+  component has declared adapted/provided interfaces, the second and third
+  arguments may be omitted.
+
+* Add support for an @provider decorator to let a function directly provide
+  an interface::
+
+    @grok.provider(IFoo, IBar)
+    def some_function():
+        ...
+
+  This is equivalent to doing alsoProvides(some_function, IFoo, IBar).
+
+* Add support for named adapters with the @adapter decorator::
+
+    @grok.adapter(IAdaptedOne, IAdaptedTwo, name=u"foo")
+    def some_function(one, two):
+        ...
+
+1.5.1 (2008-07-28)
+------------------
+
+* The ``IGrokcoreComponentAPI`` interface was missing declarations for
+  the ``title`` and ``description`` directives.
+
+1.5 (2008-07-22)
+----------------
+
+* Fix https://bugs.launchpad.net/grok/+bug/242353: grokcore.component
+  contains old-style test setup. There is no `register_all_tests`
+  method in grokcore.component.testing anymore. Use z3c.testsetup
+  instead.
+
+* Allow functions that have been marked with @grok.subscribe also be
+  registered with ``zope.component.provideHandler()`` manually.  This
+  is useful for unit tests where you may not want to grok a whole
+  module.
+
+* Document grokcore.component's public API in an interface,
+  ``IGrokcoreComponentAPI``.  When you now do::
+
+    from grokcore.component import *
+
+  only the items documented in that interface will be imported into
+  your local namespace.
+
+1.4 (2008-06-11)
+----------------
+
+* Ported class grokkers to make use of further improvements in Martian.
+  This requires Martian 0.10.
+
+1.3 (2008-05-14)
+----------------
+
+* Ported class grokkers to make use of the new declarative way of
+  retrieving directive information from a class.  This requires
+  Martian 0.9.6.
+
+1.2.1 (2008-05-04)
+------------------
+
+* Upgrade to Martian 0.9.5, which has a slight change in the signature of
+  ``scan_for_classes``.
+
+* Remove an unnecessary import ``methods_from_class`` from
+  ``grokcore.component.scan``.
+
+1.2 (2008-05-04)
+----------------
+
+* Ported directives to Martian's new directive implementation.  As a
+  result, nearly all helper functions that were available from
+  ``grokcore.component.util`` have been removed.  The functionality is
+  mostly available from the directives themselves now.
+
+* The ``baseclass`` directive has been moved to Martian.
+
+* The ``order`` directive and its helper functions have been moved
+  back to Grok, as it was of no general use, but very specific to
+  viewlets.
+
+1.1 (2008-05-03)
+----------------
+
+* ``determine_module_component`` now looks for classes that implement
+  a certain interface (such as ``IContext``), instead of taking a list
+  of classes.  If looking for ``IContext``, it still will find
+  ``Context`` subclasses, as these were also made to implement
+  ``IContext``.
+
+* Move the ``public_methods_from_class`` helper function back to Grok,
+  it isn't used at all in ``grokcore.component``.
+
+1.0.1 (2008-05-02)
+------------------
+
+* The grokkers for adapters and global utilities did not use the
+  correct value for the *provided* interface in the configuration
+  action discriminator.  Because of this, uninformative and
+  potentially wrong conflict errors would occur, as well as no
+  conflict where a conflict should have occurred.
+
+* The grokker for the ``global_utility()`` directive did immediate
+  registrations instead of generating configuration actions.
+  Therefore it did not provoke ``ConflictErrors`` for conflicting
+  registrations.
+
+* Improved documentation
+
+1.0 (2008-05-01)
+----------------
+
+* Created ``grokcore.component`` in March 2008 by factoring basic
+  component base classes and their directives and grokkers out of
+  Grok.

Added: grokcore.registries/trunk/src/grokcore.component/COPYRIGHT.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/COPYRIGHT.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/COPYRIGHT.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+Zope Foundation and Contributors
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore.component/CREDITS.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/CREDITS.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/CREDITS.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,6 @@
+CREDITS
+=======
+
+This package was extracted from the Grok web framework.
+
+For credits, see the CREDITS file in the main ``grok`` project itself.

Added: grokcore.registries/trunk/src/grokcore.component/INSTALL.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/INSTALL.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/INSTALL.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,19 @@
+Preparing for grok development
+------------------------------
+
+Install setuptools on your system, or use a setuptools-based
+environment like a "virtualenv" or a "buildout", and then install
+"grokcore.component".  Doing it from the command line looks like::
+
+    $ sudo easy_install -U grokcore.component
+
+Then you can try importing it from your Python code.
+
+Running the tests
+-----------------
+
+To run the "grokcore.component" tests, you need to download the source
+code from version control and run the following command which the
+buildout will create::
+
+    $ bin/test

Added: grokcore.registries/trunk/src/grokcore.component/LICENSE.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/LICENSE.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/LICENSE.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,44 @@
+Zope Public License (ZPL) Version 2.1
+
+A copyright notice accompanies this license document that identifies the
+copyright holders.
+
+This license has been certified as open source. It has also been designated as
+GPL compatible by the Free Software Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions in source code must retain the accompanying copyright
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying copyright
+notice, this list of conditions, and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to endorse or promote
+products derived from this software without prior written permission from the
+copyright holders.
+
+4. The right to distribute this software or to use it for any purpose does not
+give you the right to use Servicemarks (sm) or Trademarks (tm) of the
+copyright
+holders. Use of them is covered by separate agreement with the copyright
+holders.
+
+5. If any files are modified, you must cause the modified files to carry
+prominent notices stating that you changed the files and the date of any
+change.
+
+Disclaimer
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: grokcore.registries/trunk/src/grokcore.component/README.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/README.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/README.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,225 @@
+This package provides base classes of basic component types for the
+Zope Component Architecture, as well as means for configuring and
+registering them directly in Python (without ZCML).
+
+.. contents::
+
+How to set up ``grokcore.component``
+====================================
+
+In the following we assume you're writing or extending an application
+that does bootstrap configuration using ZCML.  There's always a single
+ZCML file that is executed when the application is started, which then
+includes everything else.  Let's assume this file is called
+``site.zcml`` (that's what it's called in Zope), so that file is what
+we'll be editing.
+
+In order to register the components that you wrote using the base
+classes and directives available from ``grokcore.component``, we'll
+use the ``<grok:grok />`` ZCML directive.  But before we can use it,
+we need to make sure it's available to the ZCML machinery.  We do this
+by including the meta configuration from ``grokcore.component``::
+
+  <include package="grokcore.component" file="meta.zcml" />
+
+Put this line somewhere to the top of ``site.zcml``, next to other
+meta configuration includes.  Now, further down the line, we can tell
+the machinery in ``grokcore.component`` to register all components in
+your package (let's say it's called ``helloworld``)::
+
+  <grok:grok package="helloworld" />
+
+To sum up, your ``site.zcml`` file should look like something like this::
+
+  <configure
+      xmlns="http://namespaces.zope.org/zope"
+      xmlns:grok="http://namespaces.zope.org/grok">
+
+    <!-- do the meta configuration to make the ZCML directives available -->
+    <include package="zope.foobar" file="meta.zcml" />
+    <include package="zope.frobnaz" file="meta.zcml" />
+    <include package="grokcore.component" file="meta.zcml" />
+
+    <!-- now load the configuration of packages that we depend on -->
+    <include package="zope.barfoo" />
+    <include package="zope.somethingorother" />
+
+    <!-- finally load my components which are based on grokcore.component -->
+    <grok:grok package="helloworld" />
+
+  </configure>
+
+Examples
+========
+
+Adapter
+-------
+
+Here's a simple adapter that may be useful in Zope.  It extracts the
+languages that a user prefers from the request::
+
+  import grokcore.component
+  from zope.publisher.interfaces.browser import IBrowserRequest
+  from zope.i18n.interfaces import IUserPreferredLanguages
+
+  class CookieLanguage(grokcore.component.Adapter):
+      """Extract the preferred language from a cookie"""
+      grokcore.component.context(IBrowserRequest)
+      grokcore.component.implements(IUserPreferredLanguages)
+
+      # No need to implement __init__, it's already provided by the base class.
+
+      def getPreferredLanguages(self):
+          # This an adapter for the request, so self.context is the request.
+          request = self.context
+
+          # Extract the preferred language from a cookie:
+          lang = request.cookies.get('language', 'en')
+
+          # According to IUserPreferredLanguages, we must return a list.
+          return [lang]
+
+Multi-adapter
+-------------
+
+Here's a multi-adapter that functions as a content provider as known
+from the ``zope.contentprovider`` library.  Content providers are
+components that return snippets of HTML.  They're multi-adapters for
+the content object (model), the request and the view that they're
+supposed to be a part of::
+
+  import grokcore.component
+  from zope.publisher.interfaces.browser import IBrowserRequest
+  from zope.publisher.interfaces.browser import IBrowserPage
+  from zope.contentprovider.interfaces import IContentProvider
+
+  class HelloWorldProvider(grokcore.component.MultiAdapter):
+      """Display Hello World!"""
+      grokcore.component.adapts(Interface, IBrowserRequest, IBrowserPage)
+      grokcore.component.implements(IContentProvider)
+
+      def __init__(self, context, request, view):
+          pass
+
+      def update(self):
+          pass
+
+      def render(self):
+          return u'<p>Hello World!</p>'
+
+
+Global utility
+--------------
+
+Here's a simple named utility, again from the Zope world.  It's a
+translation domain.  In other words, it contains translations of user
+messages and is invoked when the i18n machinery needs to translate
+something::
+
+  import grokcore.component
+  from zope.i18n.interfaces import ITranslationDomain
+
+  class HelloWorldTranslationDomain(grokcore.component.GlobalUtility):
+      grokcore.component.implements(ITranslationDomain)
+      grokcore.component.name('helloworld')
+
+      domain = u'helloworld'
+
+      def translate(self, msgid, mapping=None, context=None,
+                    target_language=None, default=None):
+          if target_language is None:
+              preferred = IUserPreferredLanguages(context)
+              target_language = preferred.getPreferredLanguages()[0]
+
+          translations = {'de': u'Hallo Welt',
+                          'nl': u'Hallo Wereld'}
+          return translations.get(target_language, u'Hello World')
+
+Of course, it's silly to implement your own translation domain utility
+if there are already implementations available in ``zope.i18n`` (one
+that reads translations from a GNU gettext message catalog and a
+simple implementation for tests).  Let's try to reuse that
+implementation and register an instance::
+
+  import grokcore.component
+  from zope.i18n.interfaces import ITranslationDomain
+  from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
+
+  messages = {('de', u'Hello World'): u'Hallo Welt',
+              ('nl', u'Hello World'): u'Hallo Wereld'}
+  helloworld_domain = SimpleTranslationDomain(u'helloworld', messages)
+
+  grokcore.component.global_utility(helloworld_domain,
+                                    provides=ITranslationDomain,
+                                    name='helloworld',
+                                    direct=True)
+
+Global adapter
+--------------
+
+Sometimes, you may have an object that should be registered as an adapter
+factory. It may have come from some other framework that configured that
+adapter for you, say, or you may have a class that you instantiate many
+times to get different variations on a particular adapter factory. In these
+cases, subclassing grokcore.component.Adapter or MultiAdapter is not
+possible. Instead, you can use the global_adapter() directive. Here is an
+example drawing on the ``z3c.form`` library, which provides an adapter factory
+factory for named widget attributes::
+
+  import zope.interface
+  import zope.schema
+  import grokcore.component
+  import z3c.form.widget import ComputedWidgetAttribute
+
+  class ISchema(Interface):
+      """This schema will be used to power a z3c.form form"""
+
+      field = zope.schema.TextLine(title=u"Sample field")
+
+  ...
+
+  label_override = z3c.form.widget.StaticWidgetAttribute(
+                        u"Override label", field=ISchema['field'])
+
+  grokcore.component.global_adapter(label_override, name=u"label")
+
+In the example above, the provided and adapted interfaces are deduced from the
+object returned by the ``StaticWidgetAttribute`` factory. The full syntax
+for global_adapter is::
+
+  global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
+
+The factory must be a callable (the adapter factory). Adapted interfaces are
+given as a tuple. You may use a single interface instead of a one-element
+tuple for single adapters. The provided interface is given as shown. The name
+defaults to u"" (an unnamed adapter).
+
+Handling events
+---------------
+
+Here we see an event handler much like it occurs within Zope itself. It
+subscribes to the modified event for all annotatable objects (in other words,
+objects that can have metadata associated with them). When invoked, it updates
+the Dublin Core 'Modified' property accordingly::
+
+  import datetime
+  import grokcore.component
+  from zope.annotation.interfaces import IAnnotatable
+  from zope.lifecycleevent.interfaces import IObjectModifiedEvent
+  from zope.dublincore.interfaces import IZopeDublinCore
+
+  @grokcore.component.subscribe(IAnnotatable, IObjectModifiedEvent)
+  def updateDublinCoreAfterModification(obj, event):
+      """Updated the Dublin Core 'Modified' property when a modified
+      event is sent for an object."""
+      IZopeDublinCore(obj).modified = datetime.datetime.utcnow()
+
+Subscriptions
+-------------
+
+Subscriptions look similar to Adapter, however, unlike regular adapters,
+subscription adapters are used when we want all of the adapters that adapt an
+object to a particular adapter.
+
+Analogous to MultiAdapter, there is a MultiSubscription component that "adapts"
+multiple objects.

Added: grokcore.registries/trunk/src/grokcore.component/TODO.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/TODO.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/TODO.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,6 @@
+====
+TODO
+====
+
+ - The testing infrastructure needs to be broken out into "grokcore.testing".
+ - The interfaces need to be broken out into "grokcore.interfaces".

Added: grokcore.registries/trunk/src/grokcore.component/bootstrap.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/bootstrap.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/bootstrap.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,258 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
+from optparse import OptionParser
+
+if sys.platform == 'win32':
+    def quote(c):
+        if ' ' in c:
+            return '"%s"' % c # work around spawn lamosity on windows
+        else:
+            return c
+else:
+    quote = str
+
+# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
+stdout, stderr = subprocess.Popen(
+    [sys.executable, '-Sc',
+     'try:\n'
+     '    import ConfigParser\n'
+     'except ImportError:\n'
+     '    print 1\n'
+     'else:\n'
+     '    print 0\n'],
+    stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+has_broken_dash_S = bool(int(stdout.strip()))
+
+# In order to be more robust in the face of system Pythons, we want to
+# run without site-packages loaded.  This is somewhat tricky, in
+# particular because Python 2.6's distutils imports site, so starting
+# with the -S flag is not sufficient.  However, we'll start with that:
+if not has_broken_dash_S and 'site' in sys.modules:
+    # We will restart with python -S.
+    args = sys.argv[:]
+    args[0:0] = [sys.executable, '-S']
+    args = map(quote, args)
+    os.execv(sys.executable, args)
+# Now we are running with -S.  We'll get the clean sys.path, import site
+# because distutils will do it later, and then reset the path and clean
+# out any namespace packages from site-packages that might have been
+# loaded by .pth files.
+clean_path = sys.path[:]
+import site
+sys.path[:] = clean_path
+for k, v in sys.modules.items():
+    if (hasattr(v, '__path__') and
+        len(v.__path__)==1 and
+        not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
+        # This is a namespace package.  Remove it.
+        sys.modules.pop(k)
+
+is_jython = sys.platform.startswith('java')
+
+setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
+distribute_source = 'http://python-distribute.org/distribute_setup.py'
+
+# parsing arguments
+def normalize_to_url(option, opt_str, value, parser):
+    if value:
+        if '://' not in value: # It doesn't smell like a URL.
+            value = 'file://%s' % (
+                urllib.pathname2url(
+                    os.path.abspath(os.path.expanduser(value))),)
+        if opt_str == '--download-base' and not value.endswith('/'):
+            # Download base needs a trailing slash to make the world happy.
+            value += '/'
+    else:
+        value = None
+    name = opt_str[2:].replace('-', '_')
+    setattr(parser.values, name, value)
+
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
+
+Bootstraps a buildout-based project.
+
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", dest="version",
+                          help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+                   action="store_true", dest="use_distribute", default=False,
+                   help="Use Distribute rather than Setuptools.")
+parser.add_option("--setup-source", action="callback", dest="setup_source",
+                  callback=normalize_to_url, nargs=1, type="string",
+                  help=("Specify a URL or file location for the setup file. "
+                        "If you use Setuptools, this will default to " +
+                        setuptools_source + "; if you use Distribute, this "
+                        "will default to " + distribute_source +"."))
+parser.add_option("--download-base", action="callback", dest="download_base",
+                  callback=normalize_to_url, nargs=1, type="string",
+                  help=("Specify a URL or directory for downloading "
+                        "zc.buildout and either Setuptools or Distribute. "
+                        "Defaults to PyPI."))
+parser.add_option("--eggs",
+                  help=("Specify a directory for storing eggs.  Defaults to "
+                        "a temporary directory that is deleted when the "
+                        "bootstrap script completes."))
+parser.add_option("-t", "--accept-buildout-test-releases",
+                  dest='accept_buildout_test_releases',
+                  action="store_true", default=False,
+                  help=("Normally, if you do not specify a --version, the "
+                        "bootstrap script and buildout gets the newest "
+                        "*final* versions of zc.buildout and its recipes and "
+                        "extensions for you.  If you use this flag, "
+                        "bootstrap and buildout will get the newest releases "
+                        "even if they are alphas or betas."))
+parser.add_option("-c", None, action="store", dest="config_file",
+                   help=("Specify the path to the buildout configuration "
+                         "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout's main function
+if options.config_file is not None:
+    args += ['-c', options.config_file]
+
+if options.eggs:
+    eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
+else:
+    eggs_dir = tempfile.mkdtemp()
+
+if options.setup_source is None:
+    if options.use_distribute:
+        options.setup_source = distribute_source
+    else:
+        options.setup_source = setuptools_source
+
+if options.accept_buildout_test_releases:
+    args.append('buildout:accept-buildout-test-releases=true')
+args.append('bootstrap')
+
+try:
+    import pkg_resources
+    import setuptools # A flag.  Sometimes pkg_resources is installed alone.
+    if not hasattr(pkg_resources, '_distribute'):
+        raise ImportError
+except ImportError:
+    ez_code = urllib2.urlopen(
+        options.setup_source).read().replace('\r\n', '\n')
+    ez = {}
+    exec ez_code in ez
+    setup_args = dict(to_dir=eggs_dir, download_delay=0)
+    if options.download_base:
+        setup_args['download_base'] = options.download_base
+    if options.use_distribute:
+        setup_args['no_fake'] = True
+    ez['use_setuptools'](**setup_args)
+    reload(sys.modules['pkg_resources'])
+    import pkg_resources
+    # This does not (always?) update the default working set.  We will
+    # do it.
+    for path in sys.path:
+        if path not in pkg_resources.working_set.entries:
+            pkg_resources.working_set.add_entry(path)
+
+cmd = [quote(sys.executable),
+       '-c',
+       quote('from setuptools.command.easy_install import main; main()'),
+       '-mqNxd',
+       quote(eggs_dir)]
+
+if not has_broken_dash_S:
+    cmd.insert(1, '-S')
+
+find_links = options.download_base
+if not find_links:
+    find_links = os.environ.get('bootstrap-testing-find-links')
+if find_links:
+    cmd.extend(['-f', quote(find_links)])
+
+if options.use_distribute:
+    setup_requirement = 'distribute'
+else:
+    setup_requirement = 'setuptools'
+ws = pkg_resources.working_set
+setup_requirement_path = ws.find(
+    pkg_resources.Requirement.parse(setup_requirement)).location
+env = dict(
+    os.environ,
+    PYTHONPATH=setup_requirement_path)
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+    # Figure out the most recent final version of zc.buildout.
+    import setuptools.package_index
+    _final_parts = '*final-', '*final'
+    def _final_version(parsed_version):
+        for part in parsed_version:
+            if (part[:1] == '*') and (part not in _final_parts):
+                return False
+        return True
+    index = setuptools.package_index.PackageIndex(
+        search_path=[setup_requirement_path])
+    if find_links:
+        index.add_find_links((find_links,))
+    req = pkg_resources.Requirement.parse(requirement)
+    if index.obtain(req) is not None:
+        best = []
+        bestv = None
+        for dist in index[req.project_name]:
+            distv = dist.parsed_version
+            if _final_version(distv):
+                if bestv is None or distv > bestv:
+                    best = [dist]
+                    bestv = distv
+                elif distv == bestv:
+                    best.append(dist)
+        if best:
+            best.sort()
+            version = best[-1].version
+if version:
+    requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+if is_jython:
+    import subprocess
+    exitcode = subprocess.Popen(cmd, env=env).wait()
+else: # Windows prefers this, apparently; otherwise we would prefer subprocess
+    exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
+if exitcode != 0:
+    sys.stdout.flush()
+    sys.stderr.flush()
+    print ("An error occurred when trying to install zc.buildout. "
+           "Look above this message for any errors that "
+           "were output by easy_install.")
+    sys.exit(exitcode)
+
+ws.add_entry(eggs_dir)
+ws.require(requirement)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+if not options.eggs: # clean up temporary egg directory
+    shutil.rmtree(eggs_dir)

Added: grokcore.registries/trunk/src/grokcore.component/buildout.cfg
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/buildout.cfg	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/buildout.cfg	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,20 @@
+[buildout]
+develop = .
+parts = interpreter test
+extends = http://svn.zope.org/repos/main/groktoolkit/trunk/grok.cfg
+versions = versions
+extensions = buildout.dumppickedversions
+
+[versions]
+grokcore.component =
+
+[interpreter]
+recipe = zc.recipe.egg
+eggs = grokcore.component
+interpreter = python
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = grokcore.component
+       grokcore.component[test]
+defaults = ['--tests-pattern', '^f?tests$', '-v', '--auto-color']

Added: grokcore.registries/trunk/src/grokcore.component/setup.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/setup.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/setup.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,48 @@
+from setuptools import setup, find_packages
+import os
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+long_description = (
+    read('README.txt')
+    + '\n' +
+    read('CHANGES.txt')
+    )
+
+tests_require = [
+    'zope.event',
+    ]
+
+setup(
+    name='grokcore.component',
+    version='2.5dev',
+    author='Grok Team',
+    author_email='grok-dev at zope.org',
+    url='http://grok.zope.org',
+    download_url='http://pypi.python.org/pypi/grokcore.component',
+    description='Grok-like configuration for basic components '
+                '(adapters, utilities, subscribers)',
+    long_description=long_description,
+    license='ZPL',
+    classifiers=['Intended Audience :: Developers',
+                 'License :: OSI Approved :: Zope Public License',
+                 'Programming Language :: Python',
+                 ],
+
+    packages=find_packages('src'),
+    package_dir={'': 'src'},
+    namespace_packages=['grokcore'],
+    include_package_data=True,
+    zip_safe=False,
+    install_requires=['setuptools',
+                      'martian >= 0.14',
+                      'zope.component',
+                      'zope.configuration',
+                      'zope.interface',
+                      # Note: zope.testing is NOT just a test dependency here.
+                      'zope.testing',
+                      ],
+    tests_require=tests_require,
+    extras_require={'test': tests_require},
+)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,78 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok
+"""
+
+from zope.component import adapts
+adapts.__doc__ = "Declares the types of objects that a multi-adapter adapts."
+
+from zope.interface import implements, implementsOnly, classProvides
+
+from martian import baseclass
+from martian.error import GrokError, GrokImportError
+from martian import ClassGrokker, InstanceGrokker, GlobalGrokker
+
+from grokcore.component.components import (
+    Adapter,
+    Context,
+    GlobalUtility,
+    MultiAdapter,
+    MultiSubscription,
+    Subscription,
+    )
+
+from grokcore.component.directive import (
+    context,
+    description,
+    direct,
+    global_adapter,
+    global_utility,
+    name,
+    order,
+    path,
+    provides,
+    title,
+    )
+
+from grokcore.component.decorators import (
+    adapter,
+    implementer,
+    provider,
+    subscribe,
+    )
+
+from grokcore.component.subscription import (
+    queryMultiSubscriptions,
+    queryOrderedMultiSubscriptions,
+    queryOrderedSubscriptions,
+    querySubscriptions,
+    )
+
+from grokcore.component.util import (
+    getSiteManager,
+    provideAdapter,
+    provideHandler,
+    provideInterface,
+    provideSubscriptionAdapter,
+    provideUtility,
+    sort_components,
+    )
+
+# Import this module so that it's available as soon as you import the
+# 'grokcore.component' package.  Useful for tests and interpreter examples.
+import grokcore.component.testing
+
+# Only export public API
+from grokcore.component.interfaces import IGrokcoreComponentAPI
+__all__ = list(IGrokcoreComponentAPI)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/components.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/components.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/components.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,112 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok components"""
+
+from zope.interface import implements
+
+from grokcore.component.interfaces import IContext
+
+
+class Adapter(object):
+    """Base class for an adapter that adapts a single object (commonly referred
+    to as the *context*).
+
+    Use the ``context`` directive to specify which object to adapt and the
+    ``implements`` directive to specify which interface the adapter will
+    provide. If it's a named adapter, you may use the ``name`` directive to
+    specify the name.
+
+    .. attribute:: context
+
+       The adapted object.
+
+    """
+
+    def __init__(self, context):
+        self.context = context
+
+
+class MultiAdapter(object):
+    """Base class for an adapter that adapts *n* objects (where *n>=1*).
+
+    Use the ``adapts`` directive to specify which kinds of objects are adapted
+    and the ``implements`` directive to specify which interface the adapter
+    will provide. If it's a named multi-adapter, you may use the ``name``
+    directive to specify the name.
+
+    Note that contrary to the Adapter, the MultiAdapter base class does not
+    provide an `__init__` method. An `__init__` needs to accept the same number
+    of arguments as are used in the `adapts` directive.
+
+    """
+    pass
+
+
+class GlobalUtility(object):
+    """Base class to define a globally registered utility.
+
+    Base class for a globally registered utility. Unless you use the ``direct``
+    directive to indicate that the class itself should be registered as a
+    utility, the class will automatically be instantiated, therefore the
+    constructor may not take any arguments. Use the ``implements`` directive to
+    specify which interface the utility provides, or if that is not
+    unambiguous, also use the ``provides`` directive to specify which of the
+    implemented interfaces should be used when registering the utility. If it's
+    a named utility, you may use the ``name`` directive to specify the name.
+
+    """
+    pass
+
+
+class Subscription(object):
+    """Base class for a subscription adapter.
+
+    Subscriptions are similar to adapters, except that it is possible to
+    register multiple unnamed subscriptions for identical ``context`` and
+    ``provides``.
+
+    Use the ``context`` directive to explicitly set the interface to adapt
+    from. When omitted the current context is assumed. Use the ``implements``
+    directive to specify which interface the subscription provides, or if that
+    is not unambiguous, also use the ``provides`` directive to specify which of
+    the implemented interfaces should be used when registering the subscription.
+
+    """
+
+    def __init__(self, context):
+        self.context = context
+
+
+class MultiSubscription(object):
+    """Base class for a subscription multi-adapter.
+
+    MultiSubscriptions are similar to multi adapters, except that it is
+    possible to register multiple unnamed subscriptions for identical
+    ``adapts`` and ``provides``.
+
+    Use the ``adapts`` directive to explicitly set the multiple interfaces to
+    adapt from. Use the ``implements`` directive to specify which interface the
+    subscription provides, or if that is not unambiguous, also use the
+    ``provides`` directive to specify which of the implemented interfaces
+    should be used when registering the multi subscription.
+
+    """
+
+
+class Context(object):
+    """Subclasses of this will automatically be found as potential contexts for
+    adapters and other types of context-dependent components.
+
+    """
+    implements(IContext)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/decorators.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/decorators.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/decorators.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,131 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok
+"""
+import sys
+import types
+import zope.component
+import zope.interface
+from martian.util import frame_is_module
+from martian.error import GrokImportError
+
+from zope.interface.declarations import DescriptorAwareMetaClasses
+
+class subscribe:
+    """Declares that a function is to be registered as an event handler for the
+    specified objects.
+
+    Normally, an event handler is simply registered as a subscriber for the
+    event interface. In case of object events, the event handler is registered
+    as a subscriber for the object type and the event interface.
+
+    """
+    def __init__(self, *args):
+        self.subscribed = args
+
+    def __call__(self, function):
+        frame = sys._getframe(1)
+        if not frame_is_module(frame):
+            raise GrokImportError("@grok.subscribe can only be used on module "
+                                  "level.")
+
+        if not self.subscribed:
+            raise GrokImportError("@grok.subscribe requires at least one "
+                                  "argument.")
+
+        # Add the function and subscribed interfaces to the
+        # grok.subscribers module annotation.
+        subscribers = frame.f_locals.get('__grok_subscribers__', None)
+        if subscribers is None:
+            frame.f_locals['__grok_subscribers__'] = subscribers = []
+        subscribers.append((function, self.subscribed))
+
+        # Also store the subscribed interfaces on the
+        # attribute__component_adapts__ for provideHandler to register
+        # the subscriber (in case you don't grok your package and
+        # register it manually)
+        return zope.component.adapter(*self.subscribed)(function)
+
+class adapter(zope.component.adapter):
+    """Registers the function as an adapter for the specific interface.
+
+    The ``name`` argument must be a keyword argument and is optional. If given,
+    a named adapter is registered.
+    """
+
+    # Override the z.c.adapter decorator to force sanity checking and
+    # have better error reporting and add the ability to capture the name
+
+    def __init__(self, *interfaces, **kw):
+        if not interfaces:
+            raise GrokImportError(
+                "@grok.adapter requires at least one argument.")
+        if type(interfaces[0]) is types.FunctionType:
+            raise GrokImportError(
+                "@grok.adapter requires at least one argument.")
+
+        self.name = u""
+
+        if kw:
+            if 'name' in kw:
+                self.name = kw.pop('name')
+            if kw:
+                raise GrokImportError(
+                    "@grok.adapter got unexpected keyword arguments: %s" % ','.join(kw.keys()))
+
+        zope.component.adapter.__init__(self, *interfaces)
+
+    def __call__(self, ob):
+        ob = zope.component.adapter.__call__(self, ob)
+        if self.name:
+            ob.__component_name__ = self.name
+        return ob
+
+class implementer(zope.interface.implementer):
+    """Declares that the function implements a certain interface (or a number
+    of interfaces).
+
+    This is useful when a function serves as an object factory, e.g. as an
+    adapter.
+
+    """
+
+    def __call__(self, ob):
+        # XXX we do not have function grokkers (yet) so we put the annotation
+        # on the module.
+        frame = sys._getframe(1)
+        adapters = frame.f_locals.get('__grok_adapters__', None)
+        if adapters is None:
+            frame.f_locals['__grok_adapters__'] = adapters = []
+        adapters.append(ob)
+
+        return zope.interface.implementer.__call__(self, ob)
+
+class provider:
+    """Declares that the function object provides a certain interface (or a
+    number of interfaces).
+
+    This is akin to calling directlyProvides() on the function object.
+
+    """
+    def __init__(self, *interfaces):
+        self.interfaces = interfaces
+
+    def __call__(self, ob):
+        if isinstance(ob, DescriptorAwareMetaClasses):
+            raise TypeError("Can't use implementer with classes.  Use one of "
+                            "the class-declaration functions instead."
+                            )
+        zope.interface.alsoProvides(ob, *self.interfaces)
+        return ob

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/directive.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/directive.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/directive.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,172 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok directives.
+"""
+import martian
+import martian.util
+from martian.error import GrokError, GrokImportError
+from martian.util import scan_for_classes
+from zope import interface
+from zope.interface.interfaces import IInterface
+from grokcore.component.interfaces import IContext
+
+class global_utility(martian.MultipleTimesDirective):
+    """Registers an instance of ``class`` (or ``class`` itself, depending on
+    the value of the ``direct`` parameter) as a global utility.
+
+    This allows you to register global utilities that don't inherit from the
+    ``GlobalUtility`` base class.
+
+    :param class: The class to register as a global utility.
+    :param provides: Optionally, the interface the utility will provide.
+    :param name: Optionally, a name for a named utility registration.
+    :type name: string or unicode
+    :param direct: Optionally, a flag indicating the class directly provides
+                   the interfaces, and it needs not to be instantiated.
+    :type direct: boolean
+    """
+    scope = martian.MODULE
+
+    def factory(self, factory, provides=None, name=u'', direct=False):
+        if provides is not None and not IInterface.providedBy(provides):
+            raise GrokImportError(
+                "You can only pass an interface to the "
+                "provides argument of %s." % self.name)
+        return (factory, provides, name, direct)
+
+class global_adapter(martian.MultipleTimesDirective):
+    """Registers the ``factory`` callable as a global adapter.
+
+    This allows you to register global adapters that
+    don't inherit from the ``Adapter`` or ``MultiAdapter`` base classes.
+
+    :param factory: The class that implements the adaptation.
+    :param adapts: Optionally, a single interface or a tuple of multiple
+                   interfaces to adapts from. If omitted, this information is
+                   deduced from the annotation on the factory. If no adapted
+                   interface can be determined the current context will be
+                   assumed.
+    :param provides: Optionally, the interface the adapter will provide. If
+                     omitted, this information is deduced from the annotations
+                     on the factory.
+    :param name: Optionally, a name for a named adapter registration.
+    :type name: string or unicode
+
+    """
+    scope = martian.MODULE
+
+    def factory(self, factory, adapts=None, provides=None, name=None):
+        if provides is not None and not IInterface.providedBy(provides):
+            raise GrokImportError(
+                "You can only pass an interface to the "
+                "provides argument of %s." % self.name)
+        if adapts is None:
+            adapts = getattr(factory, '__component_adapts__', None)
+        elif not isinstance(adapts, (list, tuple,)):
+            adapts = (adapts,)
+        elif isinstance(adapts, list):
+            adapts = tuple(adapts)
+
+        return (factory, adapts, provides, name)
+
+class name(martian.Directive):
+    """Declares the name of a named utility, named adapter, etc.
+
+    """
+    scope = martian.CLASS
+    store = martian.ONCE
+    validate = martian.validateText
+    default = u''
+
+class context(martian.Directive):
+    """Declares the type of object that the adapter (or a similar context-
+    dependent component) adapts.
+
+    :param context: Interface (in this case all objects providing this
+                    interface will be eligible contexts for the adaptation) or
+                    a class (then only instances of that particular class are
+                    eligible).
+    """
+
+    scope = martian.CLASS_OR_MODULE
+    store = martian.ONCE
+    validate = martian.validateInterfaceOrClass
+
+    @classmethod
+    def get_default(cls, component, module=None, **data):
+        components = list(scan_for_classes(module, IContext))
+        if len(components) == 0:
+            raise GrokError(
+                "No module-level context for %r, please use the 'context' "
+                "directive." % (component), component)
+        elif len(components) == 1:
+            component = components[0]
+        else:
+            raise GrokError(
+                "Multiple possible contexts for %r, please use the 'context' "
+                "directive."
+                % (component), component)
+        return component
+
+class title(martian.Directive):
+    """Declares the human-readable title of a component (such as a permission,
+    role, etc.)
+
+    """
+    scope = martian.CLASS
+    store = martian.ONCE
+    validate = martian.validateText
+
+class description(title):
+    pass
+
+class direct(martian.MarkerDirective):
+    """Declares that a ``GlobalUtility`` class should be registered as a
+    utility itself, rather than an instance of it.
+
+    """
+    scope = martian.CLASS
+
+class order(martian.Directive):
+    scope = martian.CLASS
+    store = martian.ONCE
+    default = 0, 0
+
+    _order = 0
+
+    def factory(self, value=0):
+        order._order += 1
+        return value, order._order
+
+class path(martian.Directive):
+    scope = martian.CLASS
+    store = martian.ONCE
+    validate = martian.validateText
+
+class provides(martian.Directive):
+    """Declares the interface that a adapter or utility provides for the
+    registration, as opposed to potentially multiple interfaces that the class
+    implements.
+
+    :param interface: The interface the registered component will provide.
+
+    """
+    scope = martian.CLASS
+    store = martian.ONCE
+    validate = martian.validateInterface
+
+    @classmethod
+    def get_default(cls, component, module, **data):
+        martian.util.check_implements_one(component)
+        return list(interface.implementedBy(component))[0]

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/interfaces.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/interfaces.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/interfaces.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,239 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Public interfaces.
+"""
+from zope.interface import Interface, Attribute
+
+class IContext(Interface):
+    """Marker interface for auto-association of context.
+
+    The ``grok.context()`` directive is used to associate adapters with the
+    class or interface they adapt. If there is only a single possible context
+    object to adapt to in a module, you can leave out this directive and
+    let the adapter associate automatically.
+
+    If you want to make an object to be a candidate for this automatic
+    association, you can subclass from ``grokcore.component.Context``.
+    This implements this ``IContext`` directive.
+
+    In some cases, you don't want to mix in a base class. You can instead
+    mark up your class with ``zope.interface.implements(IContext)`` to make
+    it a candidate for auto-association.
+    """
+
+
+class IBaseClasses(Interface):
+    Adapter = Attribute("Base class for adapters.")
+
+    ClassGrokker = Attribute("Base class to define a class grokker.")
+
+    Context = Attribute("Base class for automatically associated contexts.")
+
+    GlobalGrokker = Attribute("Base class to define a module grokker.")
+
+    GlobalUtility = Attribute("Base class for global utilities.")
+
+    InstanceGrokker = Attribute("Base class to define an instance grokker.")
+
+    MultiAdapter = Attribute("Base class for multi-adapters.")
+
+    MultiSubscription = Attribute(
+        "Base class for subscription mult-adapters.")
+
+    Subscription = Attribute("Base class for subscription adapters.")
+
+
+class IDirectives(Interface):
+
+    def baseclass():
+        """Mark this class as a base class.
+
+        This means it won't be grokked, though if it's a possible context,
+        it can still serve as a context.
+        """
+
+    def implements(*interfaces):
+        """Declare that a class implements the given interfaces."""
+
+    def implementsOnly(*interfaces):
+        """Declare that a class implements only the given interfaces.
+
+        Interfaces implemented by base classes are explicitly not inherited.
+        """
+
+    def classProvides(*interfaces):
+        """Declare that a class (as opposed to instances of the class)
+        directly provides the given interfaces.
+        """
+
+    def adapts(*classes_or_interfaces):
+        """Declare that a class adapts objects of the given classes or
+        interfaces."""
+
+    def context(class_or_interface):
+        """Declare the context for views, adapters, etc.
+
+        This directive can be used on module and class level.  When
+        used on module level, it will set the context for all views,
+        adapters, etc. in that module.  When used on class level, it
+        will set the context for that particular class."""
+
+    def name(name):
+        """Declare the name of a view or adapter/multi-adapter.
+
+        This directive can only be used on class level."""
+
+    def title(title):
+        """Set a human-readable title for a component (e.g. a
+        permission, menu item, etc.).
+
+        This directive expects pure ASCII strings or Unicode and can
+        only be used on a class level."""
+
+    def description(description):
+        """Set a human-readable description for a component (e.g. a
+        permission, menu item, etc.).
+
+        This directive expects pure ASCII strings or Unicode and can
+        only be used on a class level."""
+
+    def provides(interface):
+        """Explicitly specify with which interface a component will be
+        looked up."""
+
+    def global_utility(factory, provides=None, name=u''):
+        """Register a global utility.
+
+        factory - the factory that creates the global utility
+        provides - the interface the utility should be looked up with
+        name - the name of the utility
+        """
+
+    def global_adapter(factory, adapts=None, provides=None, name=u''):
+        """Register a global adapter.
+
+        factory - the adapter factory, a callable
+        adapts - an interface or list of interfaces adapted
+        provides - the interface provided by the adapter
+        name - the name of the adapter
+        """
+
+    def direct():
+        """Specify whether the class should be used for the component
+        or whether it should be used to instantiate the component.
+
+        This directive can be used on GlobalUtility-based classes to
+        indicate whether the class itself should be registered as a
+        utility, or an instance of it.
+        """
+
+    def order(value=None):
+        """Control the ordering of components.
+
+        If the value is specified, the order will be determined by sorting on
+        it.
+        If no value is specified, the order will be determined by definition
+        order within the module.
+        If the directive is absent, the order will be determined by class name.
+        (unfortunately our preferred default behavior on absence which would
+        be like grok.order() without argument is hard to implement in Python)
+
+        Inter-module order is by dotted name of the module the
+        components are in; unless an explicit argument is specified to
+        ``grok.order()``, components are grouped by module.
+
+        The function grok.util.sort_components can be used to sort
+        components according to these rules.
+        """
+
+
+class IDecorators(Interface):
+
+    def subscribe(*classes_or_interfaces):
+        """Declare that a function subscribes to an event or a
+        combination of objects and events."""
+
+    def adapter(*classes_or_interfaces):
+        """Describes that a function adapts an object or a combination
+        of objects.
+        """
+
+    def implementer(*interfaces):
+        """Describes that a function that's used as an adapter
+        implements an interface or a number of interfaces.
+        """
+
+    def provider(*interfaces):
+        """Describes that a function directly provides an interface or a
+        number of interfaces.
+        """
+
+
+class IGrokErrors(Interface):
+
+    def GrokError(message, component):
+        """Error indicating that a problem occurrend during the
+        grokking of a module (at "grok time")."""
+
+    def GrokImportError(*args):
+        """Error indicating a problem at import time."""
+
+
+class IMartianAPI(Interface):
+    """Part of Martian's API exposed by grokcore.component.
+    """
+
+    ClassGrokker = Attribute("Grokker for classes.")
+
+    GlobalGrokker = Attribute("Grokker that's invoked for a module.")
+
+    InstanceGrokker = Attribute("Grokker for instances.")
+
+
+class IGrokcoreComponentAPI(
+    IBaseClasses,
+    IDecorators,
+    IDirectives,
+    IGrokErrors,
+    IMartianAPI,
+    ):
+    """grokcore.component's public API.
+    """
+
+    getSiteManager = Attribute('Get the site manager for the nearest site.')
+
+    provideAdapter = Attribute('Registers an adapters')
+
+    provideHandler = Attribute('Registers an handler')
+
+    provideInterface = Attribute('Regsiters an interfaces as a utility')
+
+    provideSubscriptionAdapter = Attribute(
+        'Registers an subscriptions adapter')
+
+    provideUtility = Attribute('Registers an utility')
+
+    querySubscriptions = Attribute("Function to query subscriptions.")
+
+    queryOrderedSubscriptions = Attribute(
+        "Function to query subscription in order.")
+
+    queryMultiSubscriptions = Attribute("Function to query subscriptions.")
+
+    queryOrderedMultiSubscriptions = Attribute(
+        "Function to query subscriptions in order.")
+
+    sort_components = Attribute(
+        'Sort a list of components using the information provided by '
+        '`grok.order`.')

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,243 @@
+#############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grokkers for the various components."""
+
+import operator
+
+import martian
+import martian.util
+import grokcore.component
+import zope.component.interface
+from zope import component, interface
+from martian.error import GrokError
+from zope.interface import implementedBy
+
+def _provides(component, module=None, **data):
+    martian.util.check_implements_one(component)
+    return list(interface.implementedBy(component))[0]
+
+def default_global_utility_provides(component, module, direct, **data):
+    if direct:
+        martian.util.check_provides_one(component)
+        return list(interface.providedBy(component))[0]
+    return _provides(component)
+
+
+class AdapterGrokker(martian.ClassGrokker):
+    martian.component(grokcore.component.Adapter)
+    martian.directive(grokcore.component.context)
+    martian.directive(grokcore.component.provides)
+    martian.directive(grokcore.component.name)
+
+    def execute(self, factory, config, context, provides, name, **kw):
+        config.action(
+            discriminator=('adapter', context, provides, name),
+            callable=grokcore.component.provideAdapter,
+            args=(factory, (context,), provides, name),
+            )
+        return True
+
+
+class MultiAdapterGrokker(martian.ClassGrokker):
+    martian.component(grokcore.component.MultiAdapter)
+    martian.directive(grokcore.component.provides)
+    martian.directive(grokcore.component.name)
+
+    def execute(self, factory, config, provides, name, **kw):
+        for_ = component.adaptedBy(factory)
+        if for_ is None:
+            raise GrokError("%r must specify which contexts it adapts "
+                            "(use the 'adapts' directive to specify)."
+                            % factory, factory)
+
+        config.action(
+            discriminator=('adapter', for_, provides, name),
+            callable=grokcore.component.provideAdapter,
+            args=(factory, None, provides, name),
+            )
+        return True
+
+
+class SubscriptionGrokker(martian.ClassGrokker):
+    martian.component(grokcore.component.Subscription)
+    martian.directive(grokcore.component.context)
+    martian.directive(grokcore.component.provides)
+    martian.directive(grokcore.component.name)
+
+    def execute(self, factory, config, context, provides, name, **kw):
+        config.action(
+            discriminator=None,
+            callable=grokcore.component.provideSubscriptionAdapter,
+            args=(factory, (context,), provides),
+            )
+        return True
+
+
+class MultiSubscriptionGrokker(martian.ClassGrokker):
+    martian.component(grokcore.component.MultiSubscription)
+    martian.directive(grokcore.component.provides)
+    martian.directive(grokcore.component.name)
+
+    def execute(self, factory, config, provides, name, **kw):
+        adapts = component.adaptedBy(factory)
+        if adapts is None:
+            raise GrokError("%r must specify which contexts it adapts "
+                            "(use the 'adapts' directive to specify)."
+                            % factory, factory)
+
+        config.action(
+            discriminator=None,
+            callable=grokcore.component.provideSubscriptionAdapter,
+            args=(factory, adapts, provides),
+            )
+        return True
+
+
+class GlobalUtilityGrokker(martian.ClassGrokker):
+    martian.component(grokcore.component.GlobalUtility)
+
+    # This needs to happen before the FilesystemPageTemplateGrokker grokker
+    # happens, since it relies on the ITemplateFileFactories being grokked.
+    martian.priority(1100)
+
+    martian.directive(grokcore.component.direct)
+    martian.directive(grokcore.component.provides,
+                      get_default=default_global_utility_provides)
+    martian.directive(grokcore.component.name)
+
+    def execute(self, factory, config, direct, provides, name, **kw):
+        if not direct:
+            factory = factory()
+
+        config.action(
+            discriminator=('utility', provides, name),
+            callable=grokcore.component.provideUtility,
+            args=(factory, provides, name),
+            )
+        return True
+
+
+class ImplementerDecoratorGrokker(martian.GlobalGrokker):
+
+    def grok(self, name, module, module_info, config, **kw):
+        adapters = module_info.getAnnotation('grok.adapters', [])
+        subscribers = set(map(operator.itemgetter(0),
+                              module_info.getAnnotation('grok.subscribers', [])))
+
+        for function in adapters:
+            if function in subscribers:
+                # We don't register functions that are decorated with
+                # grok.implementer() *and* the grok.subscribe()
+                # decorator. These are registered as so called
+                # subcribers and not as regular adapters.
+                continue
+            interfaces = getattr(function, '__component_adapts__', None)
+            if interfaces is None:
+                context = grokcore.component.context.bind().get(module)
+                interfaces = (context, )
+            name = getattr(function, '__component_name__', u"")
+            config.action(
+                discriminator=('adapter', interfaces, function.__implemented__, name),
+                callable=grokcore.component.provideAdapter,
+                args=(function, interfaces, function.__implemented__, name),
+                )
+        return True
+
+class GlobalUtilityDirectiveGrokker(martian.GlobalGrokker):
+
+    def grok(self, name, module, module_info, config, **kw):
+        infos = grokcore.component.global_utility.bind().get(module)
+
+        for factory, provides, name, direct in infos:
+            if direct is None:
+                direct = grokcore.component.direct.bind().get(factory)
+            if provides is None:
+                bound = grokcore.component.provides.bind(default=None)
+                provides = bound.get(factory)
+            if not name:
+                name = grokcore.component.name.bind().get(factory)
+
+            if direct:
+                obj = factory
+                if provides is None:
+                    martian.util.check_provides_one(obj)
+                    provides = list(interface.providedBy(obj))[0]
+            else:
+                obj = factory()
+                if provides is None:
+                    provides = _provides(factory)
+
+            config.action(
+                discriminator=('utility', provides, name),
+                callable=grokcore.component.provideUtility,
+                args=(obj, provides, name),
+                )
+
+        return True
+
+
+class GlobalAdapterDirectiveGrokker(martian.GlobalGrokker):
+
+    def grok(self, name, module, module_info, config, **kw):
+        infos = grokcore.component.global_adapter.bind().get(module)
+        for factory, adapts, provides, name in infos:
+            if provides is None:
+                bound = grokcore.component.provides.bind(default=None)
+                provides = bound.get(factory)
+            if adapts is None:
+                adapts = (grokcore.component.context.bind().get(module),)
+            if name is None:
+                name = grokcore.component.name.bind().get(factory)
+
+            config.action(
+                discriminator=('adapter', adapts, provides, name),
+                callable=grokcore.component.provideAdapter,
+                args=(factory, adapts, provides, name),
+                )
+
+        return True
+
+
+class SubscriberDirectiveGrokker(martian.GlobalGrokker):
+
+    def grok(self, name, module, module_info, config, **kw):
+        subscribers = module_info.getAnnotation('grok.subscribers', [])
+
+        for factory, subscribed in subscribers:
+            provides = None
+            implemented = list(implementedBy(factory))
+            if len(implemented) == 1:
+                provides = implemented[0]
+            # provideHandler is essentially the same as
+            # provideSubscriptionAdapter, where provided=None. However,
+            # handlers and subscription adapters are tracked in
+            # separately so we cannot exchange one registration call
+            # for the the other.
+            if provides is None:
+                config.action(
+                    discriminator=None,
+                    callable=grokcore.component.provideHandler,
+                    args=(factory, subscribed))
+            else:
+                config.action(
+                    discriminator=None,
+                    callable=grokcore.component.provideSubscriptionAdapter,
+                    args=(factory, subscribed, provides))
+
+            for iface in subscribed:
+                config.action(
+                    discriminator=None,
+                    callable=grokcore.component.provideInterface,
+                    args=('', iface))
+        return True

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.zcml	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.zcml	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,17 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:meta="http://namespaces.zope.org/meta"
+    xmlns:grok="http://namespaces.zope.org/grok">
+
+  <meta:directives namespace="http://namespaces.zope.org/grok">
+    <meta:directive
+        name="grok"
+        schema=".zcml.IGrokDirective"
+        handler=".zcml.grokDirective"
+        />
+  </meta:directives>
+
+  <!-- Load the grokkers -->
+  <grok:grok package=".meta" />
+
+</configure>

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/subscription.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/subscription.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/subscription.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,41 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok subscriptions functions.
+"""
+from zope import component
+from grokcore.component import util
+
+def queryOrderedMultiSubscriptions(components, interface):
+    return util.sort_components(component.subscribers(components, interface))
+
+def queryOrderedSubscriptions(component, interface):
+    return queryOrderedMultiSubscriptions((component, ), interface)
+
+def queryMultiSubscriptions(components, interface):
+    """Query for subscriptions on the `components` providing `interface`.
+
+    :parameter components: tuple of components to lookup the subscription for.
+    :parameter interface: interface that the subscriptions should provide.
+    :return: a list of subscriptions.
+    """
+    return component.subscribers(components, interface)
+
+def querySubscriptions(component, interface):
+    """Query for subscriptions on `component` providing `interface`.
+
+    :parameter component: a component to lookup the subscriptions for.
+    :parameter interface: interface that the subscriptions should provide.
+    :return: a list of subscription.
+    """
+    return queryMultiSubscriptions((component,), interface)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,36 @@
+<html>
+<head>
+</head>
+
+<body>
+  <table class="listing">
+    <thead>
+      <tr>
+        <th class="label-column">&nbsp;</th>
+        <th>&nbsp;</th>
+      </tr>
+    </thead>
+    <tbody>
+      <tal:block repeat="widget view/widgets">
+        <tr tal:define="odd repeat/widget/odd"
+          tal:attributes="class python: odd and 'odd' or 'even'">
+          <td class="fieldname">
+            <tal:block content="widget/label"/>
+          </td>
+          <td>
+            <input tal:replace="structure widget" />
+          </td>
+        </tr>
+      </tal:block>
+    </tbody>
+    <tfoot>
+      <tr class="controls">
+        <td colspan="2" class="align-right">
+          <input tal:repeat="action view/actions" 
+            tal:replace="structure action/render" />
+        </td>
+      </tr>
+    </tfoot>
+  </table>
+</body>
+</html>

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,69 @@
+<html>
+<head>
+</head>
+
+<body>
+<form action="." tal:attributes="action request/URL" method="post"
+      class="edit-form" enctype="multipart/form-data">
+
+  <h1 i18n:translate=""
+    tal:condition="view/label"
+    tal:content="view/label">Label</h1>
+
+  <div class="form-status"
+    tal:define="status view/status"
+    tal:condition="status">
+
+    <div i18n:translate="" tal:content="view/status">
+      Form status summary
+    </div>
+
+    <ul class="errors" tal:condition="view/errors">
+      <li tal:repeat="error view/error_views">
+         <span tal:replace="structure error">Error Type</span>
+      </li>
+    </ul>
+  </div>
+
+  <table class="form-fields">
+    <tbody>
+      <tal:block repeat="widget view/widgets">
+        <tr>
+          <td class="label" tal:define="hint widget/hint">
+            <label tal:condition="python:hint"
+                   tal:attributes="for widget/name">
+              <span class="required" tal:condition="widget/required"
+              >*</span><span i18n:translate=""
+                             tal:content="widget/label">label</span>
+            </label>
+            <label tal:condition="python:not hint"
+                   tal:attributes="for widget/name">
+              <span class="required" tal:condition="widget/required"
+              >*</span><span i18n:translate=""
+                             tal:content="widget/label">label</span>
+            </label>
+          </td>
+          <td class="field">
+            <div class="widget" tal:content="structure widget">
+              <input type="text" />
+            </div>
+            <div class="error" tal:condition="widget/error">
+              <span tal:replace="structure widget/error">error</span>
+            </div>
+          </td>
+        </tr>
+      </tal:block>
+    </tbody>
+  </table>
+
+  <div id="actionsView">
+    <span class="actionButtons" tal:condition="view/availableActions">
+      <input tal:repeat="action view/actions"
+             tal:replace="structure action/render"
+             />
+    </span>
+  </div>
+</form>
+
+</body>
+</html>

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/testing.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/testing.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/testing.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,45 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok test helpers
+"""
+import grokcore.component
+from zope.configuration.config import ConfigurationMachine
+from martian import scan
+from grokcore.component import zcml
+
+def grok(module_name):
+    config = ConfigurationMachine()
+    zcml.do_grok('grokcore.component.meta', config)
+    zcml.do_grok(module_name, config)
+    config.execute_actions()
+
+def grok_component(name, component,
+                   context=None, module_info=None, templates=None):
+    if module_info is None:
+        obj_module = getattr(component, '__grok_module__', None)
+        if obj_module is None:
+            obj_module = getattr(component, '__module__', None)
+        module_info = scan.module_info_from_dotted_name(obj_module)
+
+    module = module_info.getModule()
+    if context is not None:
+        grokcore.component.context.set(module, context)
+    if templates is not None:
+        module.__grok_templates__ = templates
+    config = ConfigurationMachine()
+    result = zcml.the_multi_grokker.grok(name, component,
+                                         module_info=module_info,
+                                         config=config)
+    config.execute_actions()    
+    return result

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# make this directory a package

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,36 @@
+"""
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+  >>> home = IHome(cave)
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+
+  >>> fireplace = IFireplace(cave)
+  >>> IFireplace.providedBy(fireplace)
+  True
+  >>> isinstance(fireplace, Fireplace)
+  True
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+    pass
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome)
+
+class IFireplace(interface.Interface):
+    pass
+
+class Fireplace(grok.Adapter):
+    grok.implements(IFireplace, IHome)
+    grok.provides(IFireplace)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,90 @@
+"""
+  >>> grok.testing.grok(__name__)
+  >>>
+  >>> cave = Cave()
+  >>> home = IHome(cave)
+  >>> home.id
+  u'default'
+  >>> IHome.providedBy(home)
+  True
+  >>>
+  >>> isinstance(home, Home)
+  True
+  >>> morehome = IMoreHome(cave)
+  >>> morehome.id
+  u'default'
+  >>> IHome.providedBy(morehome)
+  True
+  >>> isinstance(morehome, Home)
+  True
+  >>> yetanotherhome = IYetAnotherHome(cave)
+  >>> IHome.providedBy(yetanotherhome)
+  True
+  >>> isinstance(yetanotherhome, Home)
+  True
+  >>> yetanotherhome.id
+  u'default'
+
+  >>> from grokcore.component.tests.adapter import noarguments_fixture
+  Traceback (most recent call last):
+  ...
+  GrokImportError: @grok.adapter requires at least one argument.
+
+  >>> from grokcore.component.tests.adapter import functionasargument_fixture
+  Traceback (most recent call last):
+  ...
+  GrokImportError: @grok.adapter requires at least one argument.
+
+  >>> from zope.component import getAdapter
+  >>> home = getAdapter(cave, IHome, name='home')
+  >>> home.id
+  u'secondary'
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class IDummy(interface.Interface):
+    pass
+
+class ICave(interface.Interface):
+    pass
+
+class IHome(interface.Interface):
+    pass
+
+class IMoreHome(interface.Interface):
+    pass
+
+class IYetAnotherHome(interface.Interface):
+    pass
+
+class Cave(grok.Context):
+    grok.implements(ICave)
+    pass
+
+class Home(object):
+    grok.implements(IHome)
+    
+    def __init__(self, id=u"default"):
+        self.id = id
+
+ at grok.adapter(Cave)
+ at grok.implementer(IHome)
+def home_for_cave(cave):
+    return Home()
+
+ at grok.adapter(ICave)
+ at grok.implementer(IMoreHome)
+def more_home_for_cave(cave):
+    return Home()
+
+ at grok.implementer(IYetAnotherHome)
+def yet_another_home_for_cave(cave):
+    return Home()
+
+ at grok.adapter(Cave, name=u"home")
+ at grok.implementer(IHome)
+def home_for_cave_named(cave):
+    return Home(u"secondary")
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,26 @@
+"""
+Grok does not depend on the alphabetical order:
+
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = ZCave()
+  >>> home = IHome(cave)
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class ZCave(grok.Context):
+    """we call this `ZCave` because we want to test that we do not
+    depend on alphabetical order"""
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,29 @@
+"""
+Explicit class-level context in case of multiple models:
+
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+  >>> home = IHome(cave)
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+    pass
+
+class Club(grok.Context):
+    pass
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome)
+    grok.context(Cave)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+"""
+Explicit class-level context for an imported model:
+
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+  >>> painting = IPainting(cave)
+
+  >>> IPainting.providedBy(painting)
+  True
+  >>> isinstance(painting, Painting)
+  True
+
+"""
+import grokcore.component as grok
+from grokcore.component.tests.adapter.adapter import Cave
+from zope import interface
+
+class IPainting(interface.Interface):
+    pass
+
+class Painting(grok.Adapter):
+    grok.implements(IPainting)
+    grok.context(Cave)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,11 @@
+"""
+You can't call grok.context multiple times on class level:
+
+  >>> import grokcore.component.tests.adapter.classcontextmultiple_fixture
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'context' directive can only be called once per
+  class or module.
+
+"""
+

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,11 @@
+import grokcore.component as grok
+
+class Cave(grok.Context):
+    pass
+
+class Club(grok.Context):
+    pass
+
+class Anything(object):
+    grok.context(Cave)
+    grok.context(Club)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,46 @@
+"""
+You can only use `grok.context` with interfaces or classes and not
+with anything else:
+
+  >>> function_context()
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'context' directive can only be called with a class or an interface.
+
+  >>> string_context()
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'context' directive can only be called with a class or an interface.
+
+  >>> module_context()
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'context' directive can only be called with a class or an interface.
+
+  >>> instance_context()
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'context' directive can only be called with a class or an interface.
+
+"""
+import grokcore.component as grok
+
+def function_context():
+    def a():
+        pass
+
+    class FunctionContext(object):
+        grok.context(a)
+
+def string_context():
+    class StringContext(object):
+        grok.context('string')
+
+def module_context():
+    class ModuleContext(object):
+        grok.context(grok)
+
+def instance_context():
+    obj = object()
+    class InstanceContext(object):
+        grok.context(obj)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,39 @@
+"""
+Registering two adapters for the same target interface should provoke
+a conflict, even if the interface is guessed (instead of being
+explicitly declared with grok.provides):
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+  ...
+  ConfigurationConflictError: Conflicting configuration actions
+    For: ('adapter', <InterfaceClass grokcore.component.tests.adapter.conflict.ICave>, <InterfaceClass grokcore.component.tests.adapter.conflict.IDecoration>, u'')
+
+"""
+import grokcore.component as grok
+from zope.interface import Interface
+
+class ICave(Interface):
+    pass
+
+class IDecoration(Interface):
+    pass
+
+class ICaveCleaning(Interface):
+    pass
+
+class Cave(object):
+    grok.implements(ICave)
+
+
+class ImplicitProvides(grok.Adapter):
+    """Here the provided interface is guessed because the class only
+    implements one interface."""
+    grok.context(ICave)
+    grok.implements(IDecoration)
+
+class ExplicitProvides(grok.Adapter):
+    """Here the provided interface is specific explicitly."""
+    grok.context(ICave)
+    grok.implements(IDecoration, ICaveCleaning)
+    grok.provides(IDecoration)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,10 @@
+import grokcore.component as grok
+from zope import interface
+
+class IDummy(interface.Interface):
+    pass
+
+ at grok.adapter
+ at grok.implementer(IDummy)
+def decorator_called_with_function_as_argument(cave):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,32 @@
+"""
+You can't call grok.context from a function:
+
+  >>> func()
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'context' directive can only be used on class or
+  module level.
+
+You can't call grok.context from a method either:
+
+  >>> SomeClass().meth()
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'context' directive can only be used on class or
+  module level.
+
+"""
+import grokcore.component as grok
+from grokcore.component.tests.adapter.adapter import Cave
+
+def func():
+    """We don't allow calling `grok.context` from anything else than a
+    module or a class"""
+    grok.context(Cave)
+
+class SomeClass(object):
+
+    def meth(self):
+        """We don't allow calling `grok.context` from anything else
+        than a module or a class"""
+        grok.context(Cave)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,149 @@
+"""
+  >>> grok.testing.grok(__name__)
+  >>> from zope.component import getAdapter, getMultiAdapter
+
+  >>> cave = Cave()
+  >>> fireplace = Fireplace()
+
+  >>> home = IHome(cave)
+  >>> home.id
+  u'one'
+
+  >>> home = getAdapter(cave, IHome, name=u"two")
+  >>> home.id
+  u'two'
+
+  >>> home = getAdapter(cave, IHome, name=u"three")
+  >>> home.id
+  u'three'
+
+  >>> home = getAdapter(cave, IHome, name=u"four")
+  >>> home.id
+  u'four'
+
+  >>> home = getAdapter(fireplace, IHome, name=u"five")
+  >>> home.id
+  u'five'
+
+  >>> home = getMultiAdapter((cave, fireplace), IHome)
+  >>> home.id
+  u'six'
+
+  >>> home = getAdapter(fireplace, IHome, name=u'seven')
+  >>> home.id
+  u'seven-a'
+
+  >>> home = getMultiAdapter((cave, fireplace), IHome, name=u'seven')
+  >>> home.id
+  u'seven-b'
+
+  >>> garage = getAdapter(cave, IGarage, name='named_garage_factory_name')
+  >>> garage.id
+  u"I'm a garage"
+
+  >>> garage = getAdapter(cave, IGarage)
+  >>> garage.id
+  u"I'm a garage"
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+from zope.interface import implementer
+
+
+class Cave(grok.Context):
+    pass
+
+
+class Fireplace(object):
+    pass
+
+
+class IHome(interface.Interface):
+    pass
+
+
+class Home(object):
+    grok.implements(IHome)
+
+    def __init__(self, id):
+        self.id = id
+
+
+class CaveHomeFactory(object):
+    grok.implements(IHome)
+
+    def __init__(self, id):
+        self.id = id
+
+    def __call__(self, context):
+        return Home(self.id)
+
+
+class CaveFireplaceHomeFactory(object):
+
+    def __init__(self, id):
+        self.id = id
+
+    def __call__(self, cave, fireplace):
+        return Home(self.id)
+
+
+factory1 = CaveHomeFactory(u"one")
+factory2 = CaveHomeFactory(u"two")
+factory3 = CaveHomeFactory(u"three")
+factory4 = CaveHomeFactory(u"four")
+factory5 = CaveHomeFactory(u"five")
+factory6 = CaveFireplaceHomeFactory(u"six")
+factory7a = CaveHomeFactory(u"seven-a")
+factory7b = CaveFireplaceHomeFactory(u"seven-b")
+
+# make some direct assertions
+
+implementer(IHome)(factory3)
+implementer(IHome)(factory4)
+implementer(IHome)(factory5)
+implementer(IHome)(factory6)
+implementer(IHome)(factory7a)
+implementer(IHome)(factory7b)
+
+grok.adapter(Fireplace)(factory5)
+grok.adapter(Fireplace)(factory7a)
+grok.adapter(Cave, Fireplace)(factory7b)
+
+# should accept single value for adapts
+grok.global_adapter(factory1, Cave, IHome)
+# should accept tuple for adapts
+grok.global_adapter(factory2, (Cave,), IHome, name=u"two")
+# should look at the provided interface
+grok.global_adapter(factory3, Cave, name=u"three")
+# should pick the canonical context
+grok.global_adapter(factory4, name=u"four")
+# should use __component_adapts__
+grok.global_adapter(factory5, name=u"five")
+# should work as multi-adapter
+grok.global_adapter(factory6, (Cave, Fireplace,))
+# should use __component_adapts__ adapting one object
+grok.global_adapter(factory7a, name=u"seven")
+# should use __component_adapts__ adaping two objects
+grok.global_adapter(factory7b, name=u"seven")
+
+
+class IGarage(interface.Interface):
+    pass
+
+
+class NamedGarageFactory(object):
+    grok.implements(IGarage)
+    grok.name('named_garage_factory_name')
+
+    def __init__(self, context):
+        self.id = u"I'm a garage"
+
+implementer(IGarage)(NamedGarageFactory)
+
+# should register a named adapter
+grok.global_adapter(NamedGarageFactory, Cave, IGarage)
+# should override component's name
+grok.global_adapter(NamedGarageFactory, Cave, IGarage, name=u'')

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+Subclasses of grok.Adapter and grok.MultiAdapter must implement exactly one
+interface:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.adapter.implementsmany.Home'> is implementing
+  more than one interface (use grok.provides to specify which one to use).
+"""
+import grokcore.component as grok
+
+from zope import interface
+
+class Cave(grok.Context):
+    pass
+
+class IHome(interface.Interface):
+    pass
+
+class IFireplace(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome, IFireplace)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,17 @@
+"""
+Subclasses of grok.Adapter and grok.MultiAdapter must implement exactly one
+interface:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.adapter.implementsnone.Home'> must
+  implement at least one interface (use grok.implements to specify).
+"""
+import grokcore.component as grok
+
+class Cave(grok.Context):
+    pass
+
+class Home(grok.Adapter):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,17 @@
+"""
+Subclasses of grok.Adapter and grok.MultiAdapter must implement exactly one
+interface:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.adapter.implementsnonemulti.Home'> must
+  implement at least one interface (use grok.implements to specify).
+"""
+import grokcore.component as grok
+
+class Cave(grok.Context):
+    pass
+
+class Home(grok.MultiAdapter):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+Imported model and adapter won't be grokked:
+
+  >>> import grokcore.component as grok
+  >>> grok.testing.grok(__name__)
+  >>> from grokcore.component.tests.adapter.adapter import IHome
+  >>> cave = Cave()
+  >>> home = IHome(cave)
+  Traceback (most recent call last):
+    ...
+  TypeError: ('Could not adapt', <grokcore.component.tests.adapter.adapter.Cave object at ...>, <InterfaceClass grokcore.component.tests.adapter.adapter.IHome>)
+
+"""
+from grokcore.component.tests.adapter.adapter import Cave, Home

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+"""
+Grok error because import model doesn't count as context:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: No module-level context for
+  <class 'grokcore.component.tests.adapter.importedmodel2.Painting'>,
+  please use the 'context' directive.
+
+"""
+import grokcore.component as grok
+from grokcore.component.tests.adapter.adapter import Cave
+from zope import interface
+
+class IPainting(interface.Interface):
+    pass
+
+class Painting(grok.Adapter):
+    """
+    Grokking of this should fail because there's no model (only an
+    imported one which doesn't count).
+    """
+    grok.implements(IPainting)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,41 @@
+"""
+You can also specify interfaces instead of classes with
+`grok.context` (class-level):
+
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+  >>> home = IHome(cave)
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+
+  >>> hole = Hole()
+  >>> home = IHome(hole)
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class ICave(interface.Interface):
+    pass
+
+class Cave(grok.Context):
+    grok.implements(ICave)
+
+class Hole(grok.Context):
+    grok.implements(ICave)
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome)
+    grok.context(ICave)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,42 @@
+"""
+You can also specify interfaces instead of classes with
+`grok.context` (module-level):
+
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+  >>> home = IHome(cave)
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+
+  >>> hole = Hole()
+  >>> home = IHome(hole)
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class ICave(interface.Interface):
+    pass
+
+class Cave(grok.Context):
+    grok.implements(ICave)
+
+class Hole(grok.Context):
+    grok.implements(ICave)
+
+grok.context(ICave)
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,30 @@
+"""
+Explicit module-level context in case of multiple models:
+
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+  >>> home = IHome(cave)
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+    pass
+
+class Club(grok.Context):
+    pass
+
+grok.context(Cave)
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+Explicit module-level context for an imported model:
+
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+  >>> painting = IPainting(cave)
+
+  >>> IPainting.providedBy(painting)
+  True
+  >>> isinstance(painting, Painting)
+  True
+
+"""
+import grokcore.component as grok
+from grokcore.component.tests.adapter.adapter import Cave
+from zope import interface
+
+grok.context(Cave)
+
+class IPainting(interface.Interface):
+    pass
+
+class Painting(grok.Adapter):
+    grok.implements(IPainting)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,10 @@
+"""
+You can't call grok.context multiple times on module level:
+
+  >>> import grokcore.component.tests.adapter.modulecontextmultiple_fixture
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'context' directive can only be called once per
+  class or module.
+
+"""

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,11 @@
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+    pass
+
+class Club(grok.Context):
+    pass
+
+grok.context(Cave)
+grok.context(Club)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,91 @@
+"""
+Multi-Adapters are supported by subclassing grok.MultiAdapter, giving
+multiple arguments to grok.adapts, and supplying a matching
+__init__():
+
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+  >>> fireplace = Fireplace()
+
+  >>> from zope import component
+  >>> home = component.getMultiAdapter((cave, fireplace))
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+  >>> home.cave is cave
+  True
+  >>> home.fireplace is fireplace
+  True
+
+This also works for named adapters using grok.name:
+
+  >>> home = component.getMultiAdapter((cave, fireplace), name='home2')
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home2)
+  True
+  >>> home.cave is cave
+  True
+  >>> home.fireplace is fireplace
+  True
+
+Multiadapters that implement more than one interface can use grok.provides to
+specify the one to use:
+
+  >>> home = component.getMultiAdapter((cave, fireplace), name='home3')
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home3)
+  True
+  >>> home.cave is cave
+  True
+  >>> home.fireplace is fireplace
+  True
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+    pass
+
+class Fireplace(grok.Context):
+    pass
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.MultiAdapter):
+    grok.adapts(Cave, Fireplace)
+    grok.implements(IHome)
+
+    def __init__(self, cave, fireplace):
+        self.cave = cave
+        self.fireplace = fireplace
+
+class Home2(grok.MultiAdapter):
+    grok.adapts(Cave, Fireplace)
+    grok.implements(IHome)
+    grok.name('home2')
+
+    def __init__(self, cave, fireplace):
+        self.cave = cave
+        self.fireplace = fireplace
+
+class IFireplace(interface.Interface):
+    pass
+
+class Home3(grok.MultiAdapter):
+    grok.adapts(Cave, Fireplace)
+    grok.implements(IHome, IFireplace)
+    grok.provides(IHome)
+    grok.name('home3')
+
+    def __init__(self, cave, fireplace):
+        self.cave = cave
+        self.fireplace = fireplace

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,18 @@
+"""
+Subclasses of grok.MultiAdapter must declare what they adapt, using grok.adapts:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.adapter.multiadaptsnone.Home'>
+  must specify which contexts it adapts (use the 'adapts' directive to specify).
+"""
+import grokcore.component as grok
+
+from zope import interface
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.MultiAdapter):
+    grok.implements(IHome)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+Multiple models lead to ambiguity:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: Multiple possible contexts for
+  <class 'grokcore.component.tests.adapter.multiple.Home'>, please use the
+  'context' directive.
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+    pass
+
+class Club(grok.Context):
+    pass
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,31 @@
+"""
+You can register a named adapter by using grok.name:
+
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+  >>> home = IHome(cave)
+  Traceback (most recent call last):
+    ...
+  TypeError: ('Could not adapt', <grokcore.component.tests.adapter.namedadapter.Cave object at 0x...>, <InterfaceClass grokcore.component.tests.adapter.namedadapter.IHome>)
+
+  >>> from zope.component import getAdapter
+  >>> home = getAdapter(cave, IHome, name='home')
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+    pass
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome)
+    grok.name('home')

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,10 @@
+import grokcore.component as grok
+from zope import interface
+
+class IDummy(interface.Interface):
+    pass
+
+ at grok.adapter()
+ at grok.implementer(IDummy)
+def decorator_called_with_no_arguments(cave):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,19 @@
+"""
+If no model can be found in the module, we get an error:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: No module-level context for
+  <class 'grokcore.component.tests.adapter.nomodel.Home'>, please use the
+  'context' directive.
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+Old-style classes are also supported:
+
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+  >>> home = IHome(cave)
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+"""
+import grokcore.component as grok
+from zope import interface
+
+class Cave:
+    pass
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome)
+    grok.context(Cave)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,26 @@
+"""
+If the model is defined after the adapter, it should still be grokked
+properly:
+
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+  >>> home = IHome(cave)
+
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IHome(interface.Interface):
+    pass
+
+class Home(grok.Adapter):
+    grok.implements(IHome)
+
+class Cave(grok.Context):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,44 @@
+"""
+  >>> grok.testing.grok(__name__)
+  
+  >>> IMarker.providedBy(not_marked)
+  False
+  >>> IMarker.providedBy(marked)
+  True
+  >>> IMarker.providedBy(double_marked)
+  True
+  
+  >>> IMarker2.providedBy(not_marked)
+  False
+  >>> IMarker2.providedBy(marked)
+  False
+  >>> IMarker2.providedBy(double_marked)
+  True
+    
+  >>> marked()
+  123
+  
+  >>> double_marked()
+  234
+  
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class IMarker(interface.Interface):
+    pass
+
+class IMarker2(interface.Interface):
+    pass
+
+ at grok.provider(IMarker)
+def marked():
+    return 123
+
+ at grok.provider(IMarker, IMarker2)
+def double_marked():
+    return 234
+
+def not_marked():
+    return 456
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,17 @@
+The grokcore.component API
+==========================
+
+The grokcore.component API is described by the
+``grokcore.component.interfaces.IGrokcoreComponentAPI`` interface.
+When you do
+
+  >>> from grokcore.component import *
+
+only those objects described in that API interface are imported into
+your local namespace.  In other words, if we take the list of things
+that have been imported and subtract the things that have been defined
+in the API interface, we'll end with pretty much nothing:
+
+  >>> from grokcore.component.interfaces import IGrokcoreComponentAPI
+  >>> sorted(set(locals()) - set(IGrokcoreComponentAPI))
+  ['IGrokcoreComponentAPI', '__builtins__', '__file__']

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+"""
+   >>> import grokcore.component.tests.directive.argumenterror_fixture
+   Traceback (most recent call last):
+     ...
+   TypeError: name takes exactly 1 argument (3 given)
+
+"""

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,4 @@
+import grokcore.component as grok
+
+class Foo(object):
+    grok.name('too', 'many', 'arguments')

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,46 @@
+"""
+Since grok.global_utility is a MultipleTimesDirective, there is a list of
+GlobalUtilityInfo objects annotated on the module.
+
+
+  >>> from martian import scan
+  >>> import grokcore.component as grok
+  >>> from grokcore.component.tests.directive import multipletimes
+  >>> guis = grok.global_utility.bind().get(multipletimes)
+  >>> len(guis)
+  2
+
+  >>> factory, provides, name, direct = guis[0]
+  >>> factory
+  <class 'grokcore.component.tests.directive.multipletimes.Club'>
+  >>> provides
+  <InterfaceClass grokcore.component.tests.directive.multipletimes.IClub>
+  >>> name
+  'foo'
+
+  >>> factory, provides, name, direct = guis[1]
+  >>> factory
+  <class 'grokcore.component.tests.directive.multipletimes.Cave'>
+  >>> provides is None
+  True
+  >>> name
+  u''
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+    pass
+
+class ICave(interface.Interface):
+    pass
+
+class Club(object):
+    grok.implements(IClub)
+
+class Cave(object):
+    grok.implements(ICave)
+
+grok.global_utility(Club, provides=IClub, name='foo')
+grok.global_utility(Cave)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,35 @@
+"""
+ at grok.subscribe can only be used on module level:
+
+  >>> function_context()
+  Traceback (most recent call last):
+    ...
+  GrokImportError: @grok.subscribe can only be used on module level.
+  
+  >>> class_context()
+  Traceback (most recent call last):
+    ...
+  GrokImportError: @grok.subscribe can only be used on module level.
+
+
+ at grok.subscribe can not be called without arguments:
+
+  >>> import grokcore.component.tests.event.errorconditions_fixture
+  Traceback (most recent call last):
+    ...
+  GrokImportError: @grok.subscribe requires at least one argument.
+  
+"""
+import grokcore.component as grok
+from zope.component.interfaces import IObjectEvent
+
+def function_context():
+    @grok.subscribe(grok.Context, IObjectEvent)
+    def subscriber():
+        pass
+    
+def class_context():
+    class Wrapper:
+        @grok.subscribe(grok.Context, IObjectEvent)
+        def subscriber(self):
+            pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,5 @@
+import grokcore.component as grok
+
+ at grok.subscribe()
+def subscriber():
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,28 @@
+"""
+When you use the @grokcore.component.subscribe decorator, you can also
+use zope.component.provideHandler to register the subscriber.  This
+can be useful for unittests where you may not want to grok everything
+in a module but just enable certain components.
+
+  >>> from zope.component import provideHandler
+  >>> provideHandler(mammothAdded)
+
+  >>> manfred = Mammoth('Manfred')
+  >>> import zope.event
+  >>> zope.event.notify(ObjectEvent(manfred))
+  >>> mammoths
+  ['Manfred']
+
+"""
+import grokcore.component as grok
+from zope.component.interfaces import IObjectEvent, ObjectEvent
+
+class Mammoth(object):
+    def __init__(self, name):
+        self.name = name
+
+mammoths = []
+
+ at grok.subscribe(Mammoth, IObjectEvent)
+def mammothAdded(mammoth, event):
+    mammoths.append(mammoth.name)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,36 @@
+"""
+You can subscribe to events using the @grok.subscribe decorator:
+
+  >>> grok.testing.grok(__name__)
+  >>> manfred = Mammoth('Manfred')
+  >>> zope.event.notify(ObjectEvent(manfred))
+  >>> mammoths
+  ['Manfred']
+  >>> mammoths2
+  ['Manfred']
+
+The decorated event handling function can also be called directly:
+
+  >>> mammothAdded(Mammoth('Max'),None)
+  >>> mammoths
+  ['Manfred', 'Max']
+
+"""
+import zope.event
+import grokcore.component as grok
+from zope.component.interfaces import IObjectEvent, ObjectEvent
+
+class Mammoth(object):
+    def __init__(self, name):
+        self.name = name
+
+mammoths = []
+mammoths2 = []
+
+ at grok.subscribe(Mammoth, IObjectEvent)
+def mammothAdded(mammoth, event):
+    mammoths.append(mammoth.name)
+
+ at grok.subscribe(Mammoth, IObjectEvent)
+def mammothAddedInstance(mammoth, event):
+    mammoths2.append(mammoth.name)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,42 @@
+Test grok_component() in an ordinary doctest.
+
+We already have tests for grok_component(), but these were placed
+inside a module. We will now test grok_component() in a pure doctest
+context. This used to demonstrate an error in martian when dealing
+with the __builtin__ module (fixed in martian 0.9.2).
+
+grokcore.component.testing.grok_component() can be used to grok individual
+components within a doctest, such as adapters. It sets up just enough
+context for some grokking to work, though more complicated grokkers
+which need module context (such as view grokkers) might not work.
+
+This defines the object we want to provide an adapter for::
+
+  >>> class Bar(object):
+  ...    pass
+
+This is the interface that we want to adapt to::
+
+  >>> from zope.interface import Interface
+  >>> class IFoo(Interface):
+  ...    pass
+
+This is the adapter itself::
+
+  >>> import grokcore.component as grok
+  >>> class MyAdapter(grok.Adapter):
+  ...    grok.provides(IFoo)
+  ...    grok.context(Bar)
+
+Now we will register the adapter using grok_component()::
+
+  >>> from grokcore.component.testing import grok, grok_component
+  >>> grok('grokcore.component.meta')
+  >>> grok_component('MyAdapter', MyAdapter)
+  True
+  
+The adapter should now be available::
+
+  >>> adapted = IFoo(Bar())
+  >>> isinstance(adapted, MyAdapter)
+  True

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,42 @@
+"""
+A Grokker can declare that scanning should continue, so that other Grokkers can
+still perform actions on the grokked components.
+
+Here we define AlphaGrokker which has higher priority than BetaGrokker but does
+not block BetaGrokker from picking up the same component::
+
+    >>> import grokcore.component as grok
+    >>> grok.testing.grok(__name__)
+
+In the fixture there is AlphaBetaSub that inherits from both Alpha and Beta.
+Thus, both Grokkers are executed, with AlphaGrokker coming before BetaGrokker::
+
+    >>> grok.testing.grok('grokcore.component.tests.grokker.continue_scanning_fixture')
+    alpha
+    beta
+
+"""
+import martian
+
+
+class Alpha(object):
+    pass
+
+class Beta(object):
+    pass
+
+class AlphaGrokker(martian.ClassGrokker):
+    martian.component(Alpha)
+    martian.priority(1) # we need to go before BetaGrokker
+
+    def grok(self, name, factory, module_info, config, **kw):
+        print "alpha"
+        return True
+
+class BetaGrokker(martian.ClassGrokker):
+    martian.component(Beta)
+
+    def grok(self, name, factory, module_info, config, **kw):
+        print "beta"
+        return True
+    

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,4 @@
+from grokcore.component.tests.grokker.continue_scanning import Alpha, Beta
+
+class AlphaBetaSub(Alpha, Beta):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,61 @@
+"""
+
+Let's first grok the meta module to define some basic grokkers::
+
+  >>> import grokcore.component as grok
+  >>> grok.testing.grok('grokcore.component.meta')
+  
+It is possible to grok an individual component. Let's define an adapter::
+
+  >>> from zope.interface import Interface
+  >>> class IMyInterface(Interface):
+  ...   pass
+  >>> class SomeClass(object):
+  ...   pass
+  >>> class MyAdapter(grok.Adapter):
+  ...   grok.provides(IMyInterface)
+  ...   grok.context(SomeClass)
+
+To grok this adapter, you can simply write this::
+
+  >>> grok.testing.grok_component('MyAdapter', MyAdapter)
+  True
+
+We can now use the adapter::
+
+  >>> instance = SomeClass()
+  >>> adapter = IMyInterface(instance)
+  >>> isinstance(adapter, MyAdapter)
+  True
+
+We can use grok_component with only two arguments because we know the
+adapter grokker is not looking for more. Sometimes we need to supply
+an extra argument however::
+
+  >>> class ISecondInterface(Interface):
+  ...   pass
+  >>> class SecondAdapter(grok.Adapter):
+  ...   grok.provides(ISecondInterface)
+
+This adapter does not supply its own context. Trying to do what we did
+before will therefore fail::
+
+  >>> grok.testing.grok_component('SecondAdapter', SecondAdapter)
+  Traceback (most recent call last):
+    ...
+  GrokError: No module-level context for <class 'grokcore.component.tests.grokker.grokcomponent.SecondAdapter'>, please use the 'context' directive.
+
+So we need to supply the context ourselves::
+
+  >>> grok.testing.grok_component('SecondAdapter', SecondAdapter, context=SomeClass)
+  True
+
+Now we can use the SecondAdapter as well::
+
+  >>> adapter = ISecondInterface(instance)
+  >>> isinstance(adapter, SecondAdapter)
+  True
+
+The next optional argument is module_info and the final argument is
+templates.
+"""

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,27 @@
+"""
+
+We define a grokker AlphaGrokker for a component called Alpha. We first need to
+grok the module defining the grokkers, in order to get them registered.
+
+Usually this would be triggered from a meta.zcml in a package, that would grok
+the module containing the grokkers (e.g. meta.py).
+
+We do it manually now::
+
+  >>> import grokcore.component as grok
+  >>> grok.testing.grok('grokcore.component.tests.grokker.onlyonce_fixture._meta')
+
+This _meta.py module then will be grokked again during 'normal' grok time. Grok
+will not re-register the grokkers as this could have unwanted side-effects. It
+will grok the components of course.
+
+NOTE: the module is called _meta to make sure it is grokked (although its
+grokker registration should be ignored) before the other files. The modules are
+picked up in alphabetical order.
+
+To simulate this, we grok the whole package::
+
+  >>> grok.testing.grok('grokcore.component.tests.grokker.onlyonce_fixture')
+  alpha
+
+"""

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# fixture package
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+import martian
+from component import Alpha
+
+class AlphaGrokker(martian.ClassGrokker):
+    martian.component(Alpha)
+
+    def grok(self, name, factory, module_info, **kw):
+        print "alpha"
+        return True

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,4 @@
+import grokcore.component as grok
+
+class Alpha(object):
+    grok.baseclass()

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,4 @@
+from component import Alpha
+
+class AlphaSub(Alpha):
+    pass
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,55 @@
+"""
+We define grokkers for the three base classes Alpha, Beta, and Gamma with different
+priorities:
+ 
+- AlphaGrokker with priority 0 (default)
+- BetaGrokker with priority 1
+- GammaGrokker with priority -1
+
+    >>> import grokcore.component as grok
+    >>> grok.testing.grok(__name__)
+
+We grok a module that implements subclasses for Alpha, Beta, and Gamma and our
+grokkers get executed in the order of priority (highest first)::
+
+    >>> grok.testing.grok('grokcore.component.tests.grokker.priority_fixture')
+    beta
+    alpha
+    gamma
+
+"""
+import martian
+
+
+class Alpha(object):
+    pass
+
+
+class Beta(object):
+    pass
+
+class Gamma(object):
+    pass
+
+class AlphaGrokker(martian.ClassGrokker):
+    martian.component(Alpha)
+
+    def grok(self, name, factory, module_info, **kw):
+        print "alpha"
+        return True
+
+class BetaGrokker(martian.ClassGrokker):
+    martian.component(Beta)
+    martian.priority(1)
+    
+    def grok(self, name, factory, module_info, **kw):
+        print "beta"
+        return True
+    
+class GammaGrokker(martian.ClassGrokker):
+    martian.component(Gamma)
+    martian.priority(-1)
+
+    def grok(self, name, factory, module_info, **kw):
+        print "gamma"
+        return True

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,10 @@
+import grokcore.component.tests.grokker.priority
+
+class AlphaSub(grokcore.component.tests.grokker.priority.Alpha):
+    pass
+
+class BetaSub(grokcore.component.tests.grokker.priority.Beta):
+    pass
+
+class GammaSub(grokcore.component.tests.grokker.priority.Gamma):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+#

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,22 @@
+"""
+We expect the module-level grok.context to be inherited by subclasses of
+an adapter that is associated with this directive. FooAdapter is such
+an adapter, defined in inherit_fixture. In this module we've inherited
+from it.
+
+Explicit module-level context for an imported model:
+
+  >>> grok.testing.grok(__name__)
+
+  >>> from zope import component
+  >>> o = component.getAdapter(inherit_fixture.Foo(), inherit_fixture.IAnder,
+  ...   name='bar')
+  >>> isinstance(o, BarAdapter)
+  True
+"""
+import grokcore.component as grok
+from grokcore.component.tests.inherit import inherit_fixture
+
+# FooAdapter has a module-level grok.context to associate it
+class BarAdapter(inherit_fixture.FooAdapter):
+    grok.name('bar')

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+import grokcore.component
+from zope.interface import Interface
+
+class Foo(grokcore.component.Context):
+    pass
+
+grokcore.component.context(Foo)
+
+class IAnder(Interface):
+    pass
+
+class FooAdapter(grokcore.component.Adapter):
+    grokcore.component.provides(IAnder)
+

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+#

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,42 @@
+"""
+If the grok.order directive is present with arguments, sorting will be
+done by the order specified.
+
+  >>> from grokcore.component import sort_components
+
+  >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
+  >>> sort_components(components)
+  [<...Fifth object at ...>,
+   <...Fourth object at ...>,
+   <...Third object at ...>,
+   <...Second object at ...>,
+   <...First object at ...>]
+
+You can use the key option:
+
+  >>> from operator import itemgetter
+
+  >>> components = [(1, First()), (2, Second()), (3, Third())]
+  >>> sort_components(components, key=itemgetter(1))
+  [(3, <...Third object at ...>),
+   (2, <...Second object at ...>),
+   (1, <...First object at ...>)]
+
+"""
+
+import grokcore.component as grok
+
+class First(object):
+    grok.order(5)
+
+class Second(object):
+    grok.order(4)
+
+class Third(object):
+    grok.order(3)
+
+class Fourth(object):
+    grok.order(2)
+
+class Fifth(object):
+    grok.order(1)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,34 @@
+"""
+
+If the grok.order directive is specified with other classes that don't
+have the order specified, then the order will be determined by first
+sorting on the order specified, and then by the definition order.
+
+  >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
+
+  >>> from grokcore.component import sort_components
+  >>> sort_components(components)
+  [<...Third object at ...>,
+   <...Fourth object at ...>,
+   <...Second object at ...>,
+   <...Fifth object at ...>,
+   <...First object at ...>]
+
+"""
+
+import grokcore.component as grok
+
+class First(object):
+    grok.order(2)
+
+class Second(object):
+    grok.order(1)
+
+class Third(object):
+    grok.order()
+
+class Fourth(object):
+    grok.order()
+
+class Fifth(object):
+    grok.order(1)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,34 @@
+"""
+
+If the grok.order directive is specified with other classes that don't
+have the order specified, then the order will be determined by first
+sorting on the order specified, and then by the definition order.
+
+  >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
+
+  >>> from grokcore.component import sort_components
+  >>> sort_components(components)
+  [<...Fifth object at ...>,
+   <...Third object at ...>,
+   <...First object at ...>,
+   <...Fourth object at ...>,
+   <...Second object at ...>]
+
+"""
+
+import grokcore.component as grok
+
+class First(object):
+    grok.order()
+
+class Second(object):
+    grok.order(1)
+
+class Third(object):
+    pass
+
+class Fourth(object):
+    grok.order()
+
+class Fifth(object):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,35 @@
+"""
+
+The ordering works like so:
+1. Objects with explicit ordering
+   (if combined with objects with no ordering not specified, then the orderless
+    objects come first)
+2. Objects with same ordering get grouped by module import order
+3. Internal order within module
+4. If no ordering is specified by any objects, then objects are sorted
+   alphabetically by class name
+
+  >>> from inter2 import Four, Five, Six
+  >>> components = [One(), Two(), Three(), Four(), Five(), Six()]
+
+  >>> from grokcore.component import sort_components
+  >>> sort_components(components)
+  [<...Three object at ...>,
+   <...One object at ...>,
+   <...Five object at ...>,
+   <...Six object at ...>,
+   <...Four object at ...>,
+   <...Two object at ...>]
+
+"""
+
+import grokcore.component as grok
+
+class One(object):
+    grok.order()
+
+class Two(object):
+    grok.order(2)
+
+class Three(object):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+This module used by inter1 tests
+"""
+
+import grokcore.component as grok
+
+class Four(object):
+    grok.order(1)
+
+class Five(object):
+    pass
+
+class Six(object):
+    grok.order()

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,33 @@
+"""
+
+If the grok.order directive is present with no arguments, sorting will
+be done by definition order.
+
+  >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
+
+  >>> from grokcore.component import sort_components
+  >>> sort_components(components)
+  [<...First object at ...>,
+   <...Second object at ...>,
+   <...Third object at ...>,
+   <...Fourth object at ...>,
+   <...Fifth object at ...>]
+
+"""
+
+import grokcore.component as grok
+
+class First(object):
+    grok.order()
+
+class Second(object):
+    grok.order()
+
+class Third(object):
+    grok.order()
+
+class Fourth(object):
+    grok.order()
+
+class Fifth(object):
+    grok.order()

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,31 @@
+"""
+
+If the grok.order directive is absent, sorting will be done by class
+name.
+
+  >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
+
+  >>> from grokcore.component import sort_components
+  >>> sort_components(components)
+  [<...Fifth object at ...>,
+   <...First object at ...>,
+   <...Fourth object at ...>,
+   <...Second object at ...>,
+   <...Third object at ...>]
+
+"""
+
+class First(object):
+    pass
+
+class Second(object):
+    pass
+
+class Third(object):
+    pass
+
+class Fourth(object):
+    pass
+
+class Fifth(object):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,41 @@
+"""
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave('sweet home')
+
+  >>> subscriptions = grok.querySubscriptions(cave, IActivity)
+  >>> subscriptions
+  [<grokcore.component.tests.subscriptions.decorator.DebuggingGrokcore object at ...>]
+
+  Subscription adapters are not registered as regular adapters:
+
+  >>> from zope import component
+  >>> component.queryAdapter(cave, IActivity)
+
+"""
+
+
+import grokcore.component as grok
+from zope import interface
+
+
+class Cave(grok.Context):
+
+    def __init__(self, name):
+        self.name = name
+
+
+class IActivity(interface.Interface):
+    pass
+
+
+class DebuggingGrokcore(object):
+
+    def __init__(self, where):
+        self.where = where
+
+
+ at grok.subscribe(Cave)
+ at grok.implementer(IActivity)
+def debugging(content):
+    return DebuggingGrokcore(content)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,98 @@
+"""
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave('Tilburg cave')
+  >>> martijn = Mammoth('Martijn')
+
+  You can query a subscriptions using multiple components. You will get
+  all subscriptions registered for office and cave (since office is a
+  base class of cave):
+
+  >>> subscriptions = grok.queryMultiSubscriptions((cave, martijn), IActivity)
+  >>> subscriptions
+  [<grokcore.component.tests.subscriptions.multisubscriptions.Sleep object at ...>,
+   <grokcore.component.tests.subscriptions.multisubscriptions.Food object at ...>,
+   <grokcore.component.tests.subscriptions.multisubscriptions.WritingCode object at ...>]
+
+  >>> _ = map(lambda s: s.do(), subscriptions)
+  Martijn is sleeping at Tilburg cave.
+  Martijn is feeding himself at Tilburg cave.
+  Martijn is writing code at Tilburg cave!
+
+
+  Now, Martijn goes to the office. You will only get subscriptions
+  registered for office:
+
+  >>> office = Office('Grok corp(r)(tm) headquarters')
+  >>> office_subscriptions = grok.queryMultiSubscriptions(
+  ...     (office, martijn), IActivity)
+  >>> office_subscriptions
+  [<grokcore.component.tests.subscriptions.multisubscriptions.Sleep object at ...>]
+
+  >>> _ = map(lambda s: s.do(), office_subscriptions)
+  Martijn is sleeping at Grok corp(r)(tm) headquarters.
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+
+class Office(grok.Context):
+
+    def __init__(self, name):
+        self.name = name
+
+
+# All caves are a kind of office.
+class Cave(Office):
+    pass
+
+
+class Mammoth(grok.Context):
+
+    def __init__(self, name):
+        self.name = name
+
+
+class IActivity(interface.Interface):
+
+    def do():
+        """Do something.
+        """
+
+class Sleep(grok.MultiSubscription):
+    grok.implements(IActivity)
+    grok.adapts(Office, Mammoth)
+
+    def __init__(self, where, who):
+        self.where = where
+        self.who = who
+
+    def do(self):
+        print '%s is sleeping at %s.' % (self.who.name, self.where.name)
+
+
+class DayTimeActivity(grok.MultiSubscription):
+    grok.implements(IActivity)
+    grok.adapts(Cave, Mammoth)
+    grok.baseclass()
+
+    def __init__(self, where, who):
+        self.where = where
+        self.who = who
+
+    def do(self):
+        print 'nothing'
+
+
+class Food(DayTimeActivity):
+
+    def do(self):
+        print '%s is feeding himself at %s.' % (self.who.name, self.where.name)
+
+
+class WritingCode(DayTimeActivity):
+
+    def do(self):
+        print '%s is writing code at %s!' % (self.who.name, self.where.name)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,19 @@
+"""
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.subscriptions.multisubscriptions_no_adapts.CaveGardenRenovator'>
+  must specify which contexts it adapts (use the 'adapts' directive to specify).
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class IRenovate(interface.Interface):
+
+    def takedown():
+        pass
+
+class CaveGardenRenovator(grok.MultiSubscription):
+    grok.provides(IRenovate)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,20 @@
+"""
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.subscriptions.multisubscriptions_no_interface.CaveGardenRedecorator'>
+  must implement at least one interface (use grok.implements to specify).
+
+"""
+
+import grokcore.component as grok
+
+
+class Cave(grok.Context):
+    pass
+
+class Garden(grok.Context):
+    pass
+
+class CaveGardenRedecorator(grok.MultiSubscription):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,97 @@
+"""
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave('Tilburg cave')
+  >>> martijn = Mammoth('Martijn')
+
+  You can query a subscriptions using multiple components and sort them
+  using `grok.order` information:
+
+  >>> ordered_subscriptions = grok.queryOrderedMultiSubscriptions(
+  ...     (cave, martijn), IActivity)
+  >>> ordered_subscriptions
+  [<grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cooking object at ...>,
+   <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Gardening object at ...>,
+   <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cleaning object at ...>]
+
+  >>> _ = map(lambda a: a.do(), ordered_subscriptions)
+  Martijn is cooking in Tilburg cave!
+  Martijn is growing pumpkins in Tilburg cave!
+  Martijn is cleaning the Tilburg cave.
+
+  Or choose not to:
+
+  >>> subscriptions = grok.queryMultiSubscriptions(
+  ...     (cave, martijn), IActivity)
+
+  (still need to sort them on class name in order to have a working doctest)
+
+  >>> subscriptions = sorted(subscriptions, key=lambda s: s.__class__.__name__)
+  >>> subscriptions
+  [<grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cleaning object at ...>,
+   <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cooking object at ...>,
+   <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Gardening object at ...>]
+
+  >>> _ = map(lambda a: a.do(), subscriptions)
+  Martijn is cleaning the Tilburg cave.
+  Martijn is cooking in Tilburg cave!
+  Martijn is growing pumpkins in Tilburg cave!
+
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+
+class Cave(grok.Context):
+
+    def __init__(self, name):
+        self.name = name
+
+
+class Mammoth(grok.Context):
+
+    def __init__(self, name):
+        self.name = name
+
+
+class IActivity(interface.Interface):
+
+    def do():
+        """Do something.
+        """
+
+
+class DayTimeActivity(grok.MultiSubscription):
+    grok.provides(IActivity)
+    grok.adapts(Cave, Mammoth)
+    grok.baseclass()
+
+    def __init__(self, where, who):
+        self.where = where
+        self.who = who
+
+    def do(self):
+        print 'Doing nothing.'
+
+
+class Cleaning(DayTimeActivity):
+    grok.order(99)
+
+    def do(self):
+        print '%s is cleaning the %s.' % (self.who.name, self.where.name)
+
+
+class Cooking(DayTimeActivity):
+    grok.order(10)
+
+    def do(self):
+        print '%s is cooking in %s!' % (self.who.name, self.where.name)
+
+
+class Gardening(DayTimeActivity):
+    grok.order(15)
+
+    def do(self):
+        print '%s is growing pumpkins in %s!' % (self.who.name, self.where.name)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,71 @@
+"""
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave()
+
+  You can query the subscriptions and sort them with the information
+  provided by grok.order:
+
+  >>> ordered_subscriptions = grok.queryOrderedSubscriptions(cave, ICleaner)
+  >>> ordered_subscriptions
+  [<grokcore.component.tests.subscriptions.ordered_subscriptions.MondayCleaner object at ...>,
+   <grokcore.component.tests.subscriptions.ordered_subscriptions.WednesdayCleaner object at ...>,
+   <grokcore.component.tests.subscriptions.ordered_subscriptions.SaturdayCleaner object at ...>]
+
+  >>> _ = map(lambda s: s.work(), ordered_subscriptions)
+  Monday cleaning!
+  Wednesday cleaning!
+  Saturday cleaning!
+
+  If you use the regular query method, they won't be sorted:
+
+  >>> subscriptions = grok.querySubscriptions(cave, ICleaner)
+  >>> subscriptions
+  [<grokcore.component.tests.subscriptions.ordered_subscriptions.MondayCleaner object at ...>,
+   <grokcore.component.tests.subscriptions.ordered_subscriptions.SaturdayCleaner object at ...>,
+   <grokcore.component.tests.subscriptions.ordered_subscriptions.WednesdayCleaner object at ...>]
+
+  >>> _ = map(lambda s: s.work(), subscriptions)
+  Monday cleaning!
+  Saturday cleaning!
+  Wednesday cleaning!
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+
+class Cave(grok.Context):
+    pass
+
+
+class ICleaner(interface.Interface):
+
+    def work():
+        """Clean that cave.
+        """
+
+class MondayCleaner(grok.Subscription):
+    grok.implements(ICleaner)
+    grok.order(1)
+
+    def work(self):
+        print 'Monday cleaning!'
+
+
+class WednesdayCleaner(grok.Subscription):
+    grok.implements(ICleaner)
+    grok.order(3)
+
+    def work(self):
+        print 'Wednesday cleaning!'
+
+
+class SaturdayCleaner(grok.Subscription):
+    grok.implements(ICleaner)
+    grok.order(6)
+
+    def work(self):
+        print 'Saturday cleaning!'
+

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,58 @@
+"""
+  >>> grok.testing.grok(__name__)
+
+  >>> cave = Cave('sweet home')
+
+  >>> subscriptions = grok.querySubscriptions(cave, ICleaner)
+  >>> subscriptions
+  [<grokcore.component.tests.subscriptions.subscriptions.MondayCleaner object at ...>,
+   <grokcore.component.tests.subscriptions.subscriptions.SaturdayCleaner object at ...>,
+   <grokcore.component.tests.subscriptions.subscriptions.WednesdayCleaner object at ...>]
+
+  >>> _ = map(lambda s: s.work(), subscriptions)
+  Monday cleaning sweet home!
+  Saturday cleaning sweet home!
+  Wednesday cleaning sweet home!
+
+  Subscription adapters are not registered as regular adapters:
+
+  >>> component.queryAdapter(cave, ICleaner)
+
+"""
+
+import grokcore.component as grok
+from zope import interface, component
+
+
+class Cave(grok.Context):
+
+    def __init__(self, name):
+        self.name = name
+
+
+class ICleaner(interface.Interface):
+
+    def work():
+        """Clean that cave.
+        """
+
+class MondayCleaner(grok.Subscription):
+    grok.implements(ICleaner)
+
+    def work(self):
+        print 'Monday cleaning %s!' % self.context.name
+
+
+class WednesdayCleaner(grok.Subscription):
+    grok.provides(ICleaner)
+
+    def work(self):
+        print 'Wednesday cleaning %s!' % self.context.name
+
+
+class SaturdayCleaner(grok.Subscription):
+    grok.implements(ICleaner)
+
+    def work(self):
+        print 'Saturday cleaning %s!' % self.context.name
+

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,20 @@
+"""
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: No module-level context for
+  <class 'grokcore.component.tests.subscriptions.subscriptions_no_context.CaveProcessor'>,
+  please use the 'context' directive.
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class ITask(interface.Interface):
+
+    def finish():
+        pass
+
+class CaveProcessor(grok.Subscription):
+    grok.provides(ITask)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,17 @@
+"""
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.subscriptions.subscriptions_no_interface.CaveProcessor'>
+  must implement at least one interface (use grok.implements to specify).
+
+"""
+
+import grokcore.component as grok
+
+
+class Cave(grok.Context):
+    pass
+
+class CaveProcessor(grok.Subscription):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,66 @@
+import re
+import unittest
+import traceback
+import doctest
+from pkg_resources import resource_listdir
+from zope.testing import cleanup, renormalizing
+import zope.component.eventtesting
+
+def setUpZope(test):
+    zope.component.eventtesting.setUp(test)
+
+def cleanUpZope(test):
+    cleanup.cleanUp()
+
+checker = renormalizing.RENormalizing([
+    # str(Exception) has changed from Python 2.4 to 2.5 (due to
+    # Exception now being a new-style class).  This changes the way
+    # exceptions appear in traceback printouts.
+    (re.compile(r"ConfigurationExecutionError: <class '([\w.]+)'>:"),
+                r'ConfigurationExecutionError: \1:'),
+    ])
+
+def suiteFromPackage(name):
+    files = resource_listdir(__name__, name)
+    suite = unittest.TestSuite()
+    for filename in files:
+        if not filename.endswith('.py'):
+            continue
+        if filename.endswith('_fixture.py'):
+            continue
+        if filename == '__init__.py':
+            continue
+
+        dottedname = 'grokcore.component.tests.%s.%s' % (name, filename[:-3])
+        try:
+            test = doctest.DocTestSuite(dottedname,
+                                        setUp=setUpZope,
+                                        tearDown=cleanUpZope,
+                                        checker=checker,
+                                        optionflags=doctest.ELLIPSIS+
+                                        doctest.NORMALIZE_WHITESPACE)
+        except ImportError:  # or should this accept anything?
+            traceback.print_exc()
+            raise
+        suite.addTest(test)
+    return suite
+
+def test_suite():
+    suite = unittest.TestSuite()
+    for name in ['adapter', 'directive', 'grokker', 'utility', 'view',
+                 'event', 'inherit', 'order', 'subscriptions']:
+        suite.addTest(suiteFromPackage(name))
+
+    api = doctest.DocFileSuite('api.txt')
+    suite.addTest(api)
+
+    # this test cannot follow the normal testing pattern, as the
+    # bug it tests for is only exposed in the context of a doctest
+    grok_component = doctest.DocFileSuite('grok_component.txt',
+                                          setUp=setUpZope,
+                                          tearDown=cleanUpZope)
+    suite.addTest(grok_component)
+    return suite
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,89 @@
+"""
+Trying to register two utilities for the same interface (and
+potentially under the same name) will generate a configuration
+conflict:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+  ...
+  ConfigurationConflictError: Conflicting configuration actions
+    For: ('utility', <InterfaceClass grokcore.component.tests.utility.conflict.IUtilityInterface>, 'class and module')
+  <BLANKLINE>
+  <BLANKLINE>
+    For: ('utility', <InterfaceClass grokcore.component.tests.utility.conflict.IUtilityInterface>, 'direct class')
+  <BLANKLINE>
+  <BLANKLINE>
+    For: ('utility', <InterfaceClass grokcore.component.tests.utility.conflict.IUtilityInterface>, 'explicit class')
+  <BLANKLINE>
+  <BLANKLINE>
+    For: ('utility', <InterfaceClass grokcore.component.tests.utility.conflict.IUtilityInterface>, 'implicit class')
+  <BLANKLINE>
+  <BLANKLINE>
+    For: ('utility', <InterfaceClass grokcore.component.tests.utility.conflict.IUtilityInterface>, 'mixed class')
+  <BLANKLINE>
+  <BLANKLINE>
+
+"""
+import grokcore.component as grok
+from zope.interface import Interface, classProvides
+
+class IUtilityInterface(Interface):
+    pass
+
+class IAnotherInterface(Interface):
+    pass
+
+
+class Implicit1(grok.GlobalUtility):
+    grok.implements(IUtilityInterface)
+    grok.name('implicit class')
+
+class Implicit2(grok.GlobalUtility):
+    grok.implements(IUtilityInterface)
+    grok.name('implicit class')
+
+
+class Explicit1(grok.GlobalUtility):
+    grok.implements(IUtilityInterface, IAnotherInterface)
+    grok.provides(IUtilityInterface)
+    grok.name('explicit class')
+
+class Explicit2(grok.GlobalUtility):
+    grok.implements(IUtilityInterface, IAnotherInterface)
+    grok.provides(IUtilityInterface)
+    grok.name('explicit class')
+
+
+class Mixed1(grok.GlobalUtility):
+    grok.implements(IUtilityInterface, IAnotherInterface)
+    grok.provides(IUtilityInterface)
+    grok.name('mixed class')
+
+class Mixed2(grok.GlobalUtility):
+    grok.implements(IUtilityInterface)
+    grok.name('mixed class')
+
+
+class Direct1(grok.GlobalUtility):
+    classProvides(IUtilityInterface)
+    grok.name('direct class')
+    grok.direct()
+
+class Direct2(grok.GlobalUtility):
+    classProvides(IUtilityInterface)
+    grok.name('direct class')
+    grok.direct()
+
+
+class ClassLevel(grok.GlobalUtility):
+    """This utility inherits from Grok's base class and is registered
+    this way."""
+    grok.implements(IUtilityInterface)
+    grok.name('class and module')
+
+class ModuleLevel(object):
+    """This utility doesn't inherit from Grok's base class and is
+    registered explicitly using the module-level directive below."""
+    grok.implements(IUtilityInterface)
+
+grok.global_utility(ModuleLevel, name='class and module')

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,21 @@
+"""
+Subclasses of grok.GlobalUtility that implement more than one interface must
+specify which interface to use for the registration:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.utility.implementsmany.Club'> is implementing
+  more than one interface (use grok.provides to specify which one to use).
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+    pass
+
+class ISpikyClub(interface.Interface):
+    pass
+
+class Club(grok.GlobalUtility):
+    grok.implements(IClub, ISpikyClub)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+"""
+Subclasses of grok.GlobalUtility that implement more than one interface must
+specify which interface to use for the registration:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.utility.implementsmany2.Club'> is implementing
+  more than one interface (use grok.provides to specify which one to use).
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+    pass
+
+class ISpikyClub(interface.Interface):
+    pass
+
+class Club(object):
+    grok.implements(IClub, ISpikyClub)
+
+grok.global_utility(Club)
+

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,13 @@
+"""
+Subclasses of grok.GlobalUtility must implement exactly one interface:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.utility.implementsnone.Club'> must
+  implement at least one interface (use grok.implements to specify).
+"""
+import grokcore.component as grok
+
+class Club(grok.GlobalUtility):
+    pass

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+"""
+Subclasses of grok.GlobalUtility must implement exactly one interface:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.utility.implementsnone2.Club'> must
+  implement at least one interface (use grok.implements to specify).
+"""
+import grokcore.component as grok
+
+class Club(object):
+    pass
+
+grok.global_utility(Club)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+"""
+Subclasses of grok.GlobalUtility that are supposed to be registered
+directly as utilities and which provide more than one interface must
+specify which interface to use for the registration:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.utility.providesmany.Club'>
+  provides more than one interface (use grok.provides to specify which one
+  to use).
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+    pass
+
+class ISpikyClub(interface.Interface):
+    pass
+
+class Club(grok.GlobalUtility):
+    interface.classProvides(IClub, ISpikyClub)
+    grok.direct()

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+Subclasses of grok.GlobalUtility that are supposed to be registered
+directly as utilities and which provide more than one interface must
+specify which interface to use for the registration:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.utility.providesmany2.Club'>
+  provides more than one interface (use grok.provides to specify which one
+  to use).
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+    pass
+
+class ISpikyClub(interface.Interface):
+    pass
+
+class Club(object):
+    interface.classProvides(IClub, ISpikyClub)
+
+grok.global_utility(Club, direct=True)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+Subclasses of grok.GlobalUtility must implement exactly one interface:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.utility.providesnone.Club'>
+  must provide at least one interface (use zope.interface.classProvides
+  to specify).
+"""
+import grokcore.component as grok
+
+class Club(grok.GlobalUtility):
+    grok.direct()

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,16 @@
+"""
+Subclasses of grok.GlobalUtility must implement exactly one interface:
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.component.tests.utility.providesnone2.Club'>
+  must provide at least one interface (use zope.interface.classProvides
+  to specify).
+"""
+import grokcore.component as grok
+
+class Club(object):
+    pass
+
+grok.global_utility(Club, direct=True)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,199 @@
+"""
+Global utilities can be created by subclassing grok.GlobalUtility:
+
+  >>> grok.testing.grok(__name__)
+  >>> from zope import component
+
+  >>> normal_club = component.getUtility(IClub)
+  >>> IClub.providedBy(normal_club)
+  True
+  >>> isinstance(normal_club, NormalClub)
+  True
+
+Named utilities are registered using grok.name:
+
+  >>> huge_club = component.getUtility(IClub, name='huge')
+  >>> IClub.providedBy(huge_club)
+  True
+  >>> isinstance(huge_club, HugeClub)
+  True
+
+A utility can explicitly specify which interface it should be looked up with.
+
+  >>> spiky_club = component.getUtility(IClub, name='spiky')
+  >>> isinstance(spiky_club, SpikyClub)
+  True
+
+  >>> component.getUtility(ISpikyClub, name='spiky')
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grokcore.component.tests.utility.utility.ISpikyClub>,
+                         'spiky')
+
+If a utility implements more than one interface, it has to specify the one to
+use with 'grok.provides':
+
+  >>> nightclub = component.getUtility(INightClub)
+  >>> INightClub.providedBy(nightclub)
+  True
+  >>> isinstance(nightclub, NightClub)
+  True
+
+You can make the class the utility by providing the grok.direct() directive,
+if you also use interface.classProvides instead of grok.provides.
+This is useful for utilities that do nothing but create instances:
+
+  >>> clubmaker = component.getUtility(IClubMaker, 'maker')
+  >>> IClubMaker.providedBy(clubmaker)
+  True
+  >>> clubmaker is ClubMaker
+  True
+
+Utilities (including classes that do not subclass from grok.GlobalUtility) can
+be (re-)registered using grok.global_utility:
+
+  >>> fireplace = component.getUtility(IFireplace)
+  >>> IFireplace.providedBy(fireplace)
+  True
+  >>> isinstance(fireplace, Fireplace)
+  True
+
+  >>> fireplace = component.getUtility(IFireplace, name='hot')
+  >>> IFireplace.providedBy(fireplace)
+  True
+  >>> isinstance(fireplace, Fireplace)
+  True
+
+  >>> home = component.getUtility(IHome)
+  >>> IHome.providedBy(home)
+  True
+  >>> isinstance(home, Home)
+  True
+
+  >>> night = component.getUtility(INightClub, name='cool')
+  >>> IClub.providedBy(night)
+  True
+  >>> isinstance(night, NightClub)
+  True
+  
+  >>> spiky = component.getUtility(ISpikyClub)
+  >>> ISpikyClub.providedBy(spiky)
+  True
+  >>> isinstance(spiky, NightClub)
+  True
+
+When re-registering a grok.GlobalUtility, the directives grok.name and
+grok.provides on the class will be used, but can be overriden in the
+grok.global_utility directive:
+
+  >>> small = component.getUtility(ISmallClub, name='tiny')
+  >>> ISmallClub.providedBy(small)
+  True
+  >>> isinstance(small, SmallClub)
+  True
+
+  >>> small2 = component.getUtility(ITinyClub, name='tiny')
+  >>> ISmallClub.providedBy(small2)
+  True
+  >>> isinstance(small2, SmallClub)
+  True
+  >>> small is not small2
+  True
+
+  >>> small3 = component.getUtility(ISmallClub, name='small')
+  >>> ISmallClub.providedBy(small3)
+  True
+  >>> isinstance(small3, SmallClub)
+  True
+  >>> small3 is not small2 and small3 is not small
+  True
+
+Normally one registers a utility factory, such as the class, as a
+global utility. It is also possible to register an arbitrary object directly
+as a global utility. You do this by passing a 'direct' argument set to
+'True'. This can be useful if one needs to register functions (such
+as factory functions) that can be looked up as a utility, or if the
+class you want to register as a global utility has an __init__ that
+takes arguments, where you want to do the instantiation yourself.
+Let's look up an instance we registered this way:
+
+  >>> small4 = component.getUtility(ISmallClub, name='smallish')
+  >>> ISmallClub.providedBy(small4)
+  True
+  >>> isinstance(small4, SmallClub)
+  True
+  
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+    pass
+
+class ISpikyClub(IClub):
+    pass
+
+class ISmallClub(IClub):
+    pass
+
+class ITinyClub(IClub):
+    pass
+
+class INightClub(interface.Interface):
+    pass
+
+class IClubMaker(interface.Interface):
+    pass
+
+class NormalClub(grok.GlobalUtility):
+    grok.implements(IClub)
+
+class HugeClub(grok.GlobalUtility):
+    grok.implements(IClub)
+    grok.name('huge')    
+
+class SpikyClub(grok.GlobalUtility):
+    grok.implements(ISpikyClub)
+    grok.provides(IClub)
+    grok.name('spiky')
+
+class NightClub(grok.GlobalUtility):
+    grok.implements(INightClub, ISpikyClub)
+    grok.provides(INightClub)
+
+class SmallClub(grok.GlobalUtility):
+    grok.implements(ISmallClub, ITinyClub)
+    grok.provides(ISmallClub)
+    grok.name('tiny')
+
+class ClubMaker(grok.GlobalUtility):
+    grok.implements(IClub)
+    interface.classProvides(IClubMaker)
+    grok.direct()
+    grok.name('maker')
+
+class IFireplace(interface.Interface):
+    pass
+
+class IHome(interface.Interface):
+    pass
+
+class Fireplace(object):
+    grok.implements(IFireplace)
+
+class Home(object):
+    grok.implements(IFireplace, IHome)
+
+grok.global_utility(Fireplace)
+grok.global_utility(Fireplace, name='hot')
+grok.global_utility(Home, provides=IHome)
+
+grok.global_utility(NightClub, name='cool')
+grok.global_utility(NightClub, provides=ISpikyClub)
+
+grok.global_utility(SmallClub, provides=ITinyClub)
+grok.global_utility(SmallClub, name='small')
+
+grok.global_utility(SmallClub(), name='smallish',
+                    direct=True)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+"""
+You can't call grok.name on a module:
+
+  >>> import grokcore.component.tests.view.nomodulename_fixture
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'name' directive can only be used on class level.
+
+"""

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,5 @@
+"""
+This should fail:
+"""
+import grokcore.component as grok
+grok.name('viewname')

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/util.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/util.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/util.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,143 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok utility functions.
+"""
+import types
+import zope.component.hooks
+from zope.interface.interfaces import IInterface
+from zope.interface import alsoProvides
+from grokcore.component import directive
+
+def _sort_key(component):
+    # If components have a grok.order directive, sort by that.
+    explicit_order, implicit_order = directive.order.bind().get(component)
+    return (explicit_order,
+            component.__module__,
+            implicit_order,
+            component.__class__.__name__)
+
+
+def sort_components(components, key=None):
+    """Sort a list of components using the information provided by
+    `grok.order`.
+    """
+    sort_key = _sort_key
+    if key is not None:
+        sort_key = lambda item: _sort_key(key(item))
+    return sorted(components, key=sort_key)
+
+
+def getSiteManager():
+    site = zope.component.hooks.getSite()
+    if site is None:
+        sm = zope.component.getGlobalSiteManager()
+    else:
+        sm = site.getSiteManager()
+    return sm
+
+
+def provideUtility(component, provides=None, name=u''):
+    sm = getSiteManager()
+    sm.registerUtility(component, provides, name, event=False)
+
+
+def provideAdapter(factory, adapts=None, provides=None, name=''):
+    sm = getSiteManager()
+    sm.registerAdapter(factory, adapts, provides, name, event=False)
+
+
+def provideSubscriptionAdapter(factory, adapts=None, provides=None):
+    sm = getSiteManager()
+    sm.registerSubscriptionAdapter(factory, adapts, provides, event=False)
+
+
+def provideHandler(factory, adapts=None):
+    sm = getSiteManager()
+    sm.registerHandler(factory, adapts, event=False)
+
+def provideInterface(id, interface, iface_type=None, info=''):
+    """register Interface with global site manager as utility
+
+    >>> gsm = zope.component.getGlobalSiteManager()
+
+    >>> from zope.interface import Interface
+    >>> from zope.interface.interfaces import IInterface
+    >>> from zope.component.tests import ITestType
+
+    >>> class I(Interface):
+    ...     pass
+    >>> IInterface.providedBy(I)
+    True
+    >>> ITestType.providedBy(I)
+    False
+    >>> interfaces = gsm.getUtilitiesFor(ITestType)
+    >>> list(interfaces)
+    []
+
+    # provide first interface type
+    >>> provideInterface('', I, ITestType)
+    >>> ITestType.providedBy(I)
+    True
+    >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
+    >>> [name for (name, iface) in interfaces]
+    [u'zope.component.interface.I']
+    >>> [iface.__name__ for (name, iface) in interfaces]
+    ['I']
+
+    # provide second interface type
+    >>> class IOtherType(IInterface):
+    ...     pass
+    >>> provideInterface('', I, IOtherType)
+
+    >>> ITestType.providedBy(I)
+    True
+    >>> IOtherType.providedBy(I)
+    True
+    >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
+    >>> [name for (name, iface) in interfaces]
+    [u'zope.component.interface.I']
+    >>> interfaces = list(gsm.getUtilitiesFor(IOtherType))
+    >>> [name for (name, iface) in interfaces]
+    [u'zope.component.interface.I']
+
+    >>> class I1(Interface):
+    ...     pass
+    >>> provideInterface('', I1)
+    >>> IInterface.providedBy(I1)
+    True
+    >>> ITestType.providedBy(I1)
+    False
+    >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
+    >>> [name for (name, iface) in interfaces]
+    [u'zope.component.interface.I']
+    >>> [iface.__name__ for (name, iface) in interfaces]
+    ['I']
+    """
+    if not id:
+        id = "%s.%s" % (interface.__module__, interface.__name__)
+
+    if not IInterface.providedBy(interface):
+        if not isinstance(interface, (type, types.ClassType)):
+            raise TypeError(id, "is not an interface or class")
+        return
+
+    if iface_type is not None:
+        if not iface_type.extends(IInterface):
+            raise TypeError(iface_type, "is not an interface type")
+        alsoProvides(interface, iface_type)
+    else:
+        iface_type = IInterface
+
+    sm = getSiteManager()
+    sm.registerUtility(interface, iface_type, id, info)

Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/zcml.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/zcml.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/zcml.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,71 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok ZCML directives."""
+
+from zope.interface import Interface
+from zope.configuration.fields import GlobalObject
+from zope.schema import TextLine
+
+import martian
+
+
+class IGrokDirective(Interface):
+    """Grok a package or module."""
+
+    package = GlobalObject(
+        title=u"Package",
+        description=u"The package or module to be analyzed by grok.",
+        required=False)
+
+    exclude = TextLine(
+        title=u"Exclude",
+        description=u"Name to exclude in the grokking process.",
+        required=False)
+
+
+# add a cleanup hook so that grok will bootstrap itself again whenever
+# the Component Architecture is torn down.
+def resetBootstrap():
+    # we need to make sure that the grokker registry is clean again
+    the_module_grokker.clear()
+
+from zope.testing.cleanup import addCleanUp
+addCleanUp(resetBootstrap)
+
+the_multi_grokker = martian.MetaMultiGrokker()
+the_module_grokker = martian.ModuleGrokker(the_multi_grokker)
+
+
+def skip_tests(name):
+    return name in ['tests', 'ftests', 'testing']
+
+
+def grokDirective(_context, package, exclude=None):
+    if not exclude:
+        exclude = None
+    do_grok(package.__name__, _context, extra_exclude=exclude)
+
+
+def do_grok(dotted_name, config, extra_exclude=None):
+    if extra_exclude is not None:
+
+        def exclude_filter(name):
+            return skip_tests(name) or extra_exclude == name
+
+    else:
+        exclude_filter = skip_tests
+
+    martian.grok_dotted_name(
+        dotted_name, the_module_grokker, exclude_filter=exclude_filter,
+        config=config)

Added: grokcore.registries/trunk/src/grokcore.site/CHANGES.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/CHANGES.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/CHANGES.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,67 @@
+Changes
+=======
+
+1.6 (unreleased)
+----------------
+
+- Moved the directive `site` from Grok to this package.
+
+- Moved the component `Application` and all the related utilities from Grok
+  to this package.
+
+
+1.5 (2011-01-03)
+----------------
+
+- Moved IApplication and getApplication from the Grok package into
+  this one.
+
+
+1.4 (2010-11-01)
+----------------
+
+- Upped versions requirements for martian and grokcore.component.
+
+1.3 (2010-10-18)
+----------------
+
+- Made package comply to repository policy.
+
+- Update functional tests to only use zope.app.appsetup instead
+  of zope.app.testing.
+
+- Update functional tests not to require zope.app.zcmlfiles
+  anymore.
+
+1.2 (2009-12-20)
+----------------
+
+* Migrated imports from zope.app.component to zope.site.
+
+1.1 (2009-09-18)
+----------------
+
+* Updated dependencies (added missing ones and added separate test
+  dependencies).
+
+* A local utility now implements IAttributeAnnotatable.
+
+* Update code documentation from Grok itself.
+
+* Use 1.0b2 versions.cfg in Grok's release info instead of a local
+  copy; a local copy for all grokcore packages is just too hard to
+  maintain.
+
+
+1.0.1 (2009-06-30)
+------------------
+
+* Reupload to pypi with a correct version of Python which doesn't have
+  a distutils bug.
+
+1.0 (2009-06-29)
+----------------
+
+* Created ``grokcore.site`` by factoring local site based components,
+  grokkers and directives out of Grok.
+

Added: grokcore.registries/trunk/src/grokcore.site/COPYRIGHT.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/COPYRIGHT.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/COPYRIGHT.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+Zope Foundation and Contributors
\ No newline at end of file

Added: grokcore.registries/trunk/src/grokcore.site/LICENSE.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/LICENSE.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/LICENSE.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,44 @@
+Zope Public License (ZPL) Version 2.1
+
+A copyright notice accompanies this license document that identifies the
+copyright holders.
+
+This license has been certified as open source. It has also been designated as
+GPL compatible by the Free Software Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions in source code must retain the accompanying copyright
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying copyright
+notice, this list of conditions, and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to endorse or promote
+products derived from this software without prior written permission from the
+copyright holders.
+
+4. The right to distribute this software or to use it for any purpose does not
+give you the right to use Servicemarks (sm) or Trademarks (tm) of the
+copyright
+holders. Use of them is covered by separate agreement with the copyright
+holders.
+
+5. If any files are modified, you must cause the modified files to carry
+prominent notices stating that you changed the files and the date of any
+change.
+
+Disclaimer
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: grokcore.registries/trunk/src/grokcore.site/README.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/README.txt	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/README.txt	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,106 @@
+
+This package provides support to write local site and utilities for
+Zope directly in Python (without ZCML).
+
+.. contents::
+
+
+Setting up ``grokcore.site``
+============================
+
+This package is essentially set up like the `grokcore.component`_
+package, please refer to its documentation for details.  The only
+additional ZCML line you will need is::
+
+  <include package="grokcore.site" />
+
+Put this somewhere near the top of your root ZCML file but below the
+line where you include ``grokcore.component``'s configuration.
+
+
+Examples
+========
+
+Global utilities are already managed by `grokcore.component`_.
+
+Here a simple example of a local utility::
+
+  from zope.interface import implements, Interface
+  import grokcore.site
+
+  class IKangaroo(Interface):
+
+      def jump():
+         """Make all kangaroos jump somewhere.
+         """
+
+  class KangarooUtility(grokcore.site.LocalUtility):
+      implements(IKangaroo)
+
+      def jump(self):
+          pass
+
+
+Now, we can register our utility to a local site. That will create
+automatically, and register that utility when we create that site::
+
+
+   class Jungle(grokcore.site.Site):
+
+       grokcore.site.local_utility(KangarooUtility, IKangaroo)
+
+
+If you don't add the last line, you will still have your site, but
+nothing to make jump your kangaroo. Then, you will be able to add
+manually by hand after (if you want).
+
+
+API Overview
+============
+
+Base classes
+------------
+
+``Site``
+   Base class for your site.
+
+``LocalUtility``
+   Base class for a ZODB-persitent local utility.
+
+
+Directives
+----------
+
+``local_utility(factory, provides=None, name=u'', setup=None, public=False, name_in_container=None``)
+   Directive used on a site to register a local utility at the
+   creation time:
+
+   ``factory``
+      Would be the component to register (required parameter),
+
+   ``provides``
+      Would be the interface used to query the local utility (required
+      parameter),
+
+   ``name``
+      Would be the name used to query the local utility,
+
+   ``setup``
+      Would be a function taking parameter. If defined it will be
+      called after the utility is created with it as first and unique
+      parameter.
+
+   ``public``
+      If true, the utility will be created in the site container
+      itself, not in the site manager, and public will be able to
+      access it directly.
+
+   ``name_in_container``
+      Would be used as id for the utility in container itwill be
+      created. If not defined it will ask NameChooser to pick a name
+      for it.
+
+In addition, the ``grokcore.site`` package exposes the
+`grokcore.component`_ API.
+
+.. _grokcore.component: http://pypi.python.org/pypi/grokcore.component

Added: grokcore.registries/trunk/src/grokcore.site/bootstrap.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/bootstrap.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/bootstrap.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,258 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
+from optparse import OptionParser
+
+if sys.platform == 'win32':
+    def quote(c):
+        if ' ' in c:
+            return '"%s"' % c # work around spawn lamosity on windows
+        else:
+            return c
+else:
+    quote = str
+
+# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
+stdout, stderr = subprocess.Popen(
+    [sys.executable, '-Sc',
+     'try:\n'
+     '    import ConfigParser\n'
+     'except ImportError:\n'
+     '    print 1\n'
+     'else:\n'
+     '    print 0\n'],
+    stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+has_broken_dash_S = bool(int(stdout.strip()))
+
+# In order to be more robust in the face of system Pythons, we want to
+# run without site-packages loaded.  This is somewhat tricky, in
+# particular because Python 2.6's distutils imports site, so starting
+# with the -S flag is not sufficient.  However, we'll start with that:
+if not has_broken_dash_S and 'site' in sys.modules:
+    # We will restart with python -S.
+    args = sys.argv[:]
+    args[0:0] = [sys.executable, '-S']
+    args = map(quote, args)
+    os.execv(sys.executable, args)
+# Now we are running with -S.  We'll get the clean sys.path, import site
+# because distutils will do it later, and then reset the path and clean
+# out any namespace packages from site-packages that might have been
+# loaded by .pth files.
+clean_path = sys.path[:]
+import site
+sys.path[:] = clean_path
+for k, v in sys.modules.items():
+    if (hasattr(v, '__path__') and
+        len(v.__path__)==1 and
+        not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
+        # This is a namespace package.  Remove it.
+        sys.modules.pop(k)
+
+is_jython = sys.platform.startswith('java')
+
+setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
+distribute_source = 'http://python-distribute.org/distribute_setup.py'
+
+# parsing arguments
+def normalize_to_url(option, opt_str, value, parser):
+    if value:
+        if '://' not in value: # It doesn't smell like a URL.
+            value = 'file://%s' % (
+                urllib.pathname2url(
+                    os.path.abspath(os.path.expanduser(value))),)
+        if opt_str == '--download-base' and not value.endswith('/'):
+            # Download base needs a trailing slash to make the world happy.
+            value += '/'
+    else:
+        value = None
+    name = opt_str[2:].replace('-', '_')
+    setattr(parser.values, name, value)
+
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
+
+Bootstraps a buildout-based project.
+
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", dest="version",
+                          help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+                   action="store_true", dest="use_distribute", default=False,
+                   help="Use Distribute rather than Setuptools.")
+parser.add_option("--setup-source", action="callback", dest="setup_source",
+                  callback=normalize_to_url, nargs=1, type="string",
+                  help=("Specify a URL or file location for the setup file. "
+                        "If you use Setuptools, this will default to " +
+                        setuptools_source + "; if you use Distribute, this "
+                        "will default to " + distribute_source +"."))
+parser.add_option("--download-base", action="callback", dest="download_base",
+                  callback=normalize_to_url, nargs=1, type="string",
+                  help=("Specify a URL or directory for downloading "
+                        "zc.buildout and either Setuptools or Distribute. "
+                        "Defaults to PyPI."))
+parser.add_option("--eggs",
+                  help=("Specify a directory for storing eggs.  Defaults to "
+                        "a temporary directory that is deleted when the "
+                        "bootstrap script completes."))
+parser.add_option("-t", "--accept-buildout-test-releases",
+                  dest='accept_buildout_test_releases',
+                  action="store_true", default=False,
+                  help=("Normally, if you do not specify a --version, the "
+                        "bootstrap script and buildout gets the newest "
+                        "*final* versions of zc.buildout and its recipes and "
+                        "extensions for you.  If you use this flag, "
+                        "bootstrap and buildout will get the newest releases "
+                        "even if they are alphas or betas."))
+parser.add_option("-c", None, action="store", dest="config_file",
+                   help=("Specify the path to the buildout configuration "
+                         "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout's main function
+if options.config_file is not None:
+    args += ['-c', options.config_file]
+
+if options.eggs:
+    eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
+else:
+    eggs_dir = tempfile.mkdtemp()
+
+if options.setup_source is None:
+    if options.use_distribute:
+        options.setup_source = distribute_source
+    else:
+        options.setup_source = setuptools_source
+
+if options.accept_buildout_test_releases:
+    args.append('buildout:accept-buildout-test-releases=true')
+args.append('bootstrap')
+
+try:
+    import pkg_resources
+    import setuptools # A flag.  Sometimes pkg_resources is installed alone.
+    if not hasattr(pkg_resources, '_distribute'):
+        raise ImportError
+except ImportError:
+    ez_code = urllib2.urlopen(
+        options.setup_source).read().replace('\r\n', '\n')
+    ez = {}
+    exec ez_code in ez
+    setup_args = dict(to_dir=eggs_dir, download_delay=0)
+    if options.download_base:
+        setup_args['download_base'] = options.download_base
+    if options.use_distribute:
+        setup_args['no_fake'] = True
+    ez['use_setuptools'](**setup_args)
+    reload(sys.modules['pkg_resources'])
+    import pkg_resources
+    # This does not (always?) update the default working set.  We will
+    # do it.
+    for path in sys.path:
+        if path not in pkg_resources.working_set.entries:
+            pkg_resources.working_set.add_entry(path)
+
+cmd = [quote(sys.executable),
+       '-c',
+       quote('from setuptools.command.easy_install import main; main()'),
+       '-mqNxd',
+       quote(eggs_dir)]
+
+if not has_broken_dash_S:
+    cmd.insert(1, '-S')
+
+find_links = options.download_base
+if not find_links:
+    find_links = os.environ.get('bootstrap-testing-find-links')
+if find_links:
+    cmd.extend(['-f', quote(find_links)])
+
+if options.use_distribute:
+    setup_requirement = 'distribute'
+else:
+    setup_requirement = 'setuptools'
+ws = pkg_resources.working_set
+setup_requirement_path = ws.find(
+    pkg_resources.Requirement.parse(setup_requirement)).location
+env = dict(
+    os.environ,
+    PYTHONPATH=setup_requirement_path)
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+    # Figure out the most recent final version of zc.buildout.
+    import setuptools.package_index
+    _final_parts = '*final-', '*final'
+    def _final_version(parsed_version):
+        for part in parsed_version:
+            if (part[:1] == '*') and (part not in _final_parts):
+                return False
+        return True
+    index = setuptools.package_index.PackageIndex(
+        search_path=[setup_requirement_path])
+    if find_links:
+        index.add_find_links((find_links,))
+    req = pkg_resources.Requirement.parse(requirement)
+    if index.obtain(req) is not None:
+        best = []
+        bestv = None
+        for dist in index[req.project_name]:
+            distv = dist.parsed_version
+            if _final_version(distv):
+                if bestv is None or distv > bestv:
+                    best = [dist]
+                    bestv = distv
+                elif distv == bestv:
+                    best.append(dist)
+        if best:
+            best.sort()
+            version = best[-1].version
+if version:
+    requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+if is_jython:
+    import subprocess
+    exitcode = subprocess.Popen(cmd, env=env).wait()
+else: # Windows prefers this, apparently; otherwise we would prefer subprocess
+    exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
+if exitcode != 0:
+    sys.stdout.flush()
+    sys.stderr.flush()
+    print ("An error occurred when trying to install zc.buildout. "
+           "Look above this message for any errors that "
+           "were output by easy_install.")
+    sys.exit(exitcode)
+
+ws.add_entry(eggs_dir)
+ws.require(requirement)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+if not options.eggs: # clean up temporary egg directory
+    shutil.rmtree(eggs_dir)

Added: grokcore.registries/trunk/src/grokcore.site/buildout.cfg
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/buildout.cfg	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/buildout.cfg	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,21 @@
+[buildout]
+develop = .
+parts = interpreter test
+extends = http://svn.zope.org/repos/main/groktoolkit/trunk/grok.cfg
+versions = versions
+extensions = buildout.dumppickedversions
+
+[versions]
+grokcore.site =
+
+[interpreter]
+recipe = zc.recipe.egg
+eggs = grokcore.site
+interpreter = python
+
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = grokcore.site
+       grokcore.site[test]
+defaults = ['--tests-pattern', '^f?tests$', '-v']

Added: grokcore.registries/trunk/src/grokcore.site/setup.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/setup.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/setup.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,58 @@
+from setuptools import setup, find_packages
+import os
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+long_description = (
+    read('README.txt')
+    + '\n' +
+    read('CHANGES.txt')
+    )
+
+tests_require = [
+    'zope.app.appsetup',
+    'zope.component',
+    'zope.configuration',
+    'zope.location',
+    'zope.testing',
+    'grokcore.content',
+    ]
+
+setup(
+    name='grokcore.site',
+    version='1.6dev',
+    author='Grok Team',
+    author_email='grok-dev at zope.org',
+    url='http://grok.zope.org',
+    download_url='http://pypi.python.org/pypi/grokcore.site',
+    description='Grok-like configuration for Zope local site and utilities',
+    long_description=long_description,
+    license='ZPL',
+    classifiers=['Environment :: Web Environment',
+                 'Intended Audience :: Developers',
+                 'License :: OSI Approved :: Zope Public License',
+                 'Programming Language :: Python',
+                 'Framework :: Zope3',
+                 ],
+
+    packages=find_packages('src'),
+    package_dir={'': 'src'},
+    namespace_packages=['grokcore'],
+    include_package_data=True,
+    zip_safe=False,
+    install_requires=['setuptools',
+                      'ZODB3',
+                      'zope.event',
+                      'grokcore.component >= 2.1',
+                      'martian >= 0.13',
+                      'zope.annotation',
+                      'zope.component',
+                      'zope.container',
+                      'zope.interface',
+                      'zope.lifecycleevent',
+                      'zope.site',
+                      ],
+    tests_require=tests_require,
+    extras_require={'test': tests_require},
+)

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+##############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from zope.site.hooks import getSite
+from grokcore.component import *
+from grokcore.site.directive import site, local_utility
+from grokcore.site.components import Site, LocalUtility, Application
+from grokcore.site.util import getApplication
+
+import grokcore.site.testing
+
+from grokcore.site.interfaces import IGrokcoreSiteAPI
+__all__ = list(IGrokcoreSiteAPI)

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/components.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/components.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/components.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,79 @@
+##############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from persistent import Persistent
+from grokcore.component.interfaces import IContext
+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.site.site import SiteManagerContainer
+
+
+class BaseSite(object):
+    """Mixin to grok sites in Grok applications.
+
+    It's used to let different implementation of sites to exists, and
+    still being grokked correctly.
+    """
+
+
+class Site(BaseSite, SiteManagerContainer):
+    """Mixin for creating sites in Grok applications.
+
+    When an application :class:`grok.Model` or :class:`grok.Container`
+    also inherits from :class:`grokcore.site.Site`, then it can
+    additionally support the registration of local Component
+    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):
+    """The base class for local utilities in Grok applications.
+
+    Defines a utility that will be registered local to a :class:`Site`
+    or :class:`grok.Application`.
+    
+    Although application developers can create local utilies without
+    actually subclassing :class:`LocalUtility`, they gain three
+    benefits from doing so.  First, their code is more readable
+    because their classes "look like" local utilities to casual
+    readers.  Second, their utility will know how to persist itself to
+    the Zope database, which means that they can set its object
+    attributes and know that the values are getting automatically
+    saved.  Third, they can omit the `grok.provides()` directive
+    naming the interface that the utility provides, if their class
+    only `grok.implements()` a single interface (unless the interface
+    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.registries/trunk/src/grokcore.site/src/grokcore/site/configure.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/configure.zcml	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/configure.zcml	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,13 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    xmlns:grok="http://namespaces.zope.org/grok">
+
+  <include package="." file="meta.zcml" />
+  <include package="zope.component" file="meta.zcml" />
+  <include package="zope.component" />
+
+  <grok:grok package=".subscriber" />
+  <utility component=".meta.setupUtility" />
+
+</configure>

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/directive.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/directive.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/directive.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,151 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok directives.
+"""
+
+import grokcore.component
+
+from grokcore.site.components import LocalUtility
+
+from zope import interface
+from zope.interface.interfaces import IInterface
+
+import martian
+from martian import util
+from martian.error import GrokImportError
+
+
+class site(martian.Directive):
+    """This directive is used to indicate the Grok site
+    object for which the component should be used/registered.
+    """
+    scope = martian.CLASS
+    store = martian.ONCE
+    validate = martian.validateInterfaceOrClass
+
+
+class local_utility(martian.Directive):
+    """The `grokcore.site.local_utility()` directive.
+
+    Place this directive inside of a `grokcore.site.Site` subclass,
+    and provide the name of a utility you want activated inside of
+    that site::
+
+        class MySite(grokcore.site.Site):
+            grok.local_utility(MyMammothUtility)
+            ...
+
+    This directive can be supplied several times within the same site.
+    Thanks to the presence of this directive, any time an instance of
+    your class is created in the Zope database it will have a copy of
+    the given local utility installed along with it.
+
+    This directive accepts several normal Component-registration keyword
+    arguments, like `provides` and `name`, and uses them each time it
+    registers your local utility.
+
+    If you do not supply a `provides` keyword, then Grok attempts to
+    guess a sensible default.  Its first choice is to use any
+    interface(s) that you listed with the grok.provides() directive
+    when defining your utility.  Otherwise, if your utility is a
+    subclass of `grokcore.site.LocalUtility`, then Grok will use any
+    interfaces that your utility supplies beyond those are supplied
+    because of its inheritance from `grokcore.site.LocalUtility`.
+    Else, as a final fallback, it checks to see whether the class you
+    are registering supplies one, and only one, interface; if so, then
+    it can register the utility unambiguously as providing that one
+    interface.
+
+    """
+
+    scope = martian.CLASS
+    store = martian.DICT
+
+    def factory(self, factory, provides=None, name=u'',
+                setup=None, public=False, name_in_container=None):
+        if provides is not None and not IInterface.providedBy(provides):
+            raise GrokImportError("You can only pass an interface to the "
+                                  "provides argument of %s." % self.name)
+
+        if provides is None:
+            # We cannot bind the provides directive and get information
+            # from the factory, so we do it "manually" as we know how
+            # to get to the information.
+            dotted = grokcore.component.provides.dotted_name()
+            provides = getattr(factory, dotted, None)
+
+        if provides is None:
+            if util.check_subclass(factory, LocalUtility):
+                baseInterfaces = interface.implementedBy(LocalUtility)
+                utilityInterfaces = interface.implementedBy(factory)
+                provides = list(utilityInterfaces - baseInterfaces)
+
+                if len(provides) == 0 and len(list(utilityInterfaces)) > 0:
+                    raise GrokImportError(
+                        "Cannot determine which interface to use "
+                        "for utility registration of %r. "
+                        "It implements an interface that is a specialization "
+                        "of an interface implemented by grok.LocalUtility. "
+                        "Specify the interface by either using grok.provides "
+                        "on the utility or passing 'provides' to "
+                        "grok.local_utility." % factory, factory)
+            else:
+                provides = list(interface.implementedBy(factory))
+
+            util.check_implements_one_from_list(provides, factory)
+            provides = provides[0]
+
+        if (provides, name) in self.frame.f_locals.get(self.dotted_name(), {}):
+            raise GrokImportError(
+                "Conflicting local utility registration %r. "
+                "Local utilities are registered multiple "
+                "times for interface %r and name %r." %
+                (factory, provides, name), factory)
+
+        info = LocalUtilityInfo(factory, provides, name, setup, public,
+                                name_in_container)
+        return (provides, name), info
+
+
+class LocalUtilityInfo(object):
+    """The information about how to register a local utility.
+
+    An instance of this class is created for each
+    `grokcore.site.local_utility()` in a Grok application's code, to
+    remember how the user wants their local utility registered.
+    Later, whenever the application creates new instances of the site
+    or application for which the local utility directive was supplied,
+    this block of information is used as the parameters to the
+    creation of the local utility which is created along with the new
+    site in the Zope database.
+
+    """
+    _order = 0
+
+    def __init__(self, factory, provides, name=u'',
+                 setup=None, public=False, name_in_container=None):
+        self.factory = factory
+        self.provides = provides
+        self.name = name
+        self.setup = setup
+        self.public = public
+        self.name_in_container = name_in_container
+
+        self.order = LocalUtilityInfo._order
+        LocalUtilityInfo._order += 1
+
+    def __cmp__(self, other):
+        # LocalUtilityInfos have an inherit sort order by which the
+        # registrations take place.
+        return cmp(self.order, other.order)

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftesting.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftesting.zcml	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftesting.zcml	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+<configure
+   xmlns="http://namespaces.zope.org/zope"
+   xmlns:grok="http://namespaces.zope.org/grok"
+   xmlns:browser="http://namespaces.zope.org/browser"
+   i18n_domain="grokcore.site"
+   package="grokcore.site">
+
+  <include package="zope.app.appsetup" file="ftesting.zcml" />
+
+  <include package="grokcore.site" file="meta.zcml" />
+  <include package="grokcore.site" />
+
+  <grok:grok package="grokcore.site.ftests" />
+
+</configure>

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/application.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/application.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/application.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -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.
+    """

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/site.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/site.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/site.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,51 @@
+"""
+A site can be created by mixing in grok.Site into a grok.Model or
+grok.Container.
+
+  >>> from zope import interface
+  >>> from zope.location.interfaces import IPossibleSite, ISite
+  >>> manfred = Mammoth()
+  >>> IPossibleSite.providedBy(manfred)
+  True
+  >>> herd = Herd()
+  >>> IPossibleSite.providedBy(herd)
+  True
+  >>> nonsite = NonSite()
+  >>> IPossibleSite.providedBy(nonsite)
+  False
+  >>> nonsitecontainer = NonSiteContainer()
+  >>> IPossibleSite.providedBy(nonsitecontainer)
+  False
+
+While manfred and herd are possible sites, they are not yet sites;
+
+  >>> ISite.providedBy(manfred)
+  False
+  >>> ISite.providedBy(herd)
+  False
+  
+When a site is added to a container it will be initialized as a site
+(when the ObjectAddedEvent is fired):
+
+  >>> nonsitecontainer['manfred'] = manfred
+  >>> ISite.providedBy(manfred)
+  True
+  >>> nonsitecontainer['herd'] = herd
+  >>> ISite.providedBy(herd)
+  True
+"""
+import grokcore.site
+from persistent import Persistent
+from zope.container.btree import BTreeContainer
+
+class Mammoth(grokcore.site.Site):
+    pass
+
+class Herd(grokcore.site.Site):
+    pass
+
+class NonSite(Persistent):
+    pass
+
+class NonSiteContainer(BTreeContainer):
+    pass

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/test_grok_functional.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/test_grok_functional.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/test_grok_functional.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,40 @@
+import unittest
+import grokcore.site
+
+from pkg_resources import resource_listdir
+from zope.testing import doctest
+from zope.app.appsetup.testlayer import ZODBLayer
+
+FunctionalLayer = ZODBLayer(grokcore.site)
+
+
+def suiteFromPackage(name):
+    files = resource_listdir(__name__, name)
+    suite = unittest.TestSuite()
+    for filename in files:
+        if not filename.endswith('.py'):
+            continue
+        if filename == '__init__.py':
+            continue
+
+        dottedname = 'grokcore.site.ftests.%s.%s' % (name, filename[:-3])
+        test = doctest.DocTestSuite(
+            dottedname,
+            extraglobs=dict(getRootFolder=FunctionalLayer.getRootFolder),
+            optionflags=(doctest.ELLIPSIS+
+                         doctest.NORMALIZE_WHITESPACE+
+                         doctest.REPORT_NDIFF)
+            )
+        test.layer = FunctionalLayer
+
+        suite.addTest(test)
+    return suite
+
+def test_suite():
+    suite = unittest.TestSuite()
+    for name in ['utility', 'site', 'application']:
+        suite.addTest(suiteFromPackage(name))
+    return suite
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,141 @@
+"""
+Local Utilities can be registered on subclasses of grok.Site using
+grok.local_utility:
+
+  >>> cave = Cave()
+  >>> getRootFolder()["cave"] = cave
+
+  >>> from zope import component
+  >>> from zope.site.hooks import getSite, setSite
+  >>> setSite(cave)
+
+  >>> fireplace = component.getUtility(IFireplace)
+  >>> IFireplace.providedBy(fireplace)
+  True
+  >>> isinstance(fireplace, Fireplace)
+  True
+
+  >>> club = component.getUtility(IClub)
+  >>> IClub.providedBy(club)
+  True
+  >>> isinstance(club, Club)
+  True
+
+  >>> spiky = component.getUtility(IClub, name='spiky')
+  >>> IClub.providedBy(spiky)
+  True
+  >>> isinstance(spiky, SpikyClub)
+  True
+
+  >>> mammoth = component.getUtility(IMammoth)
+  >>> IMammoth.providedBy(mammoth)
+  True
+  >>> isinstance(mammoth, Mammoth)
+  True
+
+  >>> tiger = component.getUtility(IMammoth, name='tiger')
+  >>> IMammoth.providedBy(tiger)
+  True
+  >>> isinstance(tiger, SabretoothTiger)
+  True
+
+  >>> painting = component.getUtility(IPainting, name='blackandwhite')
+  >>> IPainting.providedBy(painting)
+  True
+  >>> isinstance(painting, CavePainting)
+  True
+
+  >>> colored = component.getUtility(IPainting, name='color')
+  >>> IPainting.providedBy(colored)
+  True
+  >>> isinstance(colored, ColoredCavePainting)
+  True
+
+Since it is a local utility, it is not available outside its site:
+
+  >>> setSite(None)
+  >>> component.getUtility(IFireplace)
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IFireplace>, '')
+
+  >>> component.getUtility(IClub)
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IClub>, '')
+
+  >>> component.getUtility(IClub, name='spiky')
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IClub>, 'spiky')
+
+  >>> component.getUtility(IMammoth)
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IMammoth>, '')
+
+  >>> component.getUtility(IMammoth, name='tiger')
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IMammoth>, 'tiger')
+
+  >>> component.getUtility(IPainting, name='blackandwhite')
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IPainting>, 'blackandwhite')
+
+  >>> component.getUtility(IPainting, name='color')
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IPainting>, 'color')
+"""
+import grokcore.site
+from zope import interface
+import persistent
+
+class IFireplace(interface.Interface):
+    pass
+
+class IClub(interface.Interface):
+    pass
+
+class ISpiky(interface.Interface):
+    pass
+
+class IMammoth(interface.Interface):
+    pass
+
+class Fireplace(grokcore.site.LocalUtility):
+    interface.implements(IFireplace)
+
+class Club(object):
+    interface.implements(IClub)
+
+class SpikyClub(object):
+    interface.implements(IClub, ISpiky)
+
+class Mammoth(grokcore.site.LocalUtility):
+    interface.implements(IMammoth, IClub)
+
+class SabretoothTiger(grokcore.site.LocalUtility):
+    interface.implements(IMammoth, IClub)
+    grokcore.site.provides(IMammoth)
+
+class IPainting(persistent.interfaces.IPersistent):
+    pass
+
+class CavePainting(grokcore.site.LocalUtility):
+    interface.implements(IPainting)
+
+class ColoredCavePainting(grokcore.site.LocalUtility):
+    interface.implements(IPainting)
+    grokcore.site.provides(IPainting)
+
+class Cave(grokcore.site.Site):
+    grokcore.site.local_utility(Fireplace)
+    grokcore.site.local_utility(Club)
+    grokcore.site.local_utility(SpikyClub, provides=IClub, name='spiky')
+    grokcore.site.local_utility(Mammoth, provides=IMammoth)
+    grokcore.site.local_utility(SabretoothTiger, name='tiger')
+    grokcore.site.local_utility(CavePainting, name='blackandwhite', provides=IPainting)
+    grokcore.site.local_utility(ColoredCavePainting, name='color')

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local_override.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local_override.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local_override.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,38 @@
+"""
+Local Utilities can be registered on subclasses of grok.Site using
+grok.local_utility:
+
+  >>> cave = SpikyCave()
+  >>> getRootFolder()['cave'] = cave
+
+  >>> from zope import component
+  >>> from zope.site.hooks import getSite, setSite
+  >>> setSite(cave)
+
+  >>> club = component.getUtility(IClub)
+  >>> IClub.providedBy(club)
+  True
+  >>> isinstance(club, SpikyClub)
+  True
+
+  >>> list(cave.getSiteManager().keys())
+  [u'SpikyClub']
+"""
+import grokcore.site
+from zope import interface
+
+class IClub(interface.Interface):
+    pass
+
+class Club(grokcore.site.LocalUtility):
+    interface.implements(IClub)
+
+class SpikyClub(grokcore.site.LocalUtility):
+    interface.implements(IClub)
+
+class Cave(grokcore.site.Site):
+    grokcore.site.local_utility(Club)
+
+class SpikyCave(Cave):
+    grokcore.site.local_utility(SpikyClub)
+

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/public.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/public.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/public.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,44 @@
+"""
+By default, a utility is not in the public site; it's in ++etc++site. We can
+also specify the utility to be public. It will then be created in the container
+that is the site. The name the utility should have in the container can
+be controlled using name_in_container:
+
+  >>> cave = Cave()
+  >>> getRootFolder()["cave"] = cave
+
+  >>> from zope import component
+  >>> from zope.site.hooks import getSite, setSite
+  >>> setSite(cave)
+  >>> cave['fireplace'] is component.getUtility(IFireplace)
+  True
+
+name_in_container can also be used for objects stored under the site manager
+(that is in ++etc++site):
+
+   >>> cave2 = Cave2()
+   >>> getRootFolder()['cave2'] = cave2
+   >>> setSite(cave2)
+   >>> (cave2.getSiteManager()['fireplace'] is
+   ...  component.getUtility(IFireplace))
+   True
+
+"""
+
+import grokcore.site
+from zope import interface
+from zope.container.btree import BTreeContainer
+
+class IFireplace(interface.Interface):
+    pass
+
+class Fireplace(grokcore.site.LocalUtility):
+    interface.implements(IFireplace)
+    
+class Cave(BTreeContainer, grokcore.site.Site):
+    grokcore.site.local_utility(Fireplace, public=True,
+                                name_in_container='fireplace')
+
+class Cave2(BTreeContainer, grokcore.site.Site):
+    grokcore.site.local_utility(Fireplace, public=False,
+                                name_in_container='fireplace')

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/subclass.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/subclass.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/subclass.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,101 @@
+"""
+Subclassed sites inherit all local utilities of their base classes:
+
+  >>> cave = BigCave()
+  >>> getRootFolder()["cave"] = cave
+
+  >>> from zope import component
+  >>> from zope.site.hooks import getSite, setSite
+
+  >>> setSite(cave)
+  >>> fireplace = component.getUtility(IFireplace)
+  >>> IFireplace.providedBy(fireplace)
+  True
+  >>> isinstance(fireplace, Fireplace)
+  True
+
+Additional utilities can be registered in the subclass:
+  
+  >>> hollow = HollowCave()
+  >>> getRootFolder()["hollow"] = hollow
+
+  >>> setSite(hollow)
+  >>> fireplace = component.getUtility(IFireplace)
+  >>> IFireplace.providedBy(fireplace)
+  True
+  >>> isinstance(fireplace, Fireplace)
+  True
+
+  >>> painting = component.getUtility(IPainting)
+  >>> IPainting.providedBy(painting)
+  True
+  >>> isinstance(painting, Painting)
+  True
+
+Those do not influence the base class:
+
+  >>> setSite(cave)
+  >>> painting = component.getUtility(IPainting)
+  Traceback (most recent call last):
+    ...
+  ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.subclass.IPainting>, '')
+
+This works various levels of inheritance deep:
+
+  >>> very_hollow = VeryHollowCave()
+  >>> getRootFolder()['very_hollow'] = very_hollow
+
+  >>> setSite(very_hollow)
+  >>> fireplace = component.getUtility(IFireplace)
+  >>> painting = component.getUtility(IPainting)
+  >>> great_painting = component.getUtility(IPainting, 'great')
+  >>> bad_painting = component.getUtility(IPainting, 'bad')
+
+And with inheritance hierarchies where a base class is inherited multiple
+times through different routes:
+
+  >>> scary = ScaryCave()
+  >>> getRootFolder()['scary'] = scary
+
+  >>> setSite(scary)
+  >>> fireplace = component.getUtility(IFireplace)
+  >>> painting = component.getUtility(IPainting)
+  >>> great_painting = component.getUtility(IPainting, 'great')
+  >>> bad_painting = component.getUtility(IPainting, 'bad')
+
+"""
+import grokcore.site
+from zope import interface
+
+class IFireplace(interface.Interface):
+    pass
+
+class IPainting(interface.Interface):
+    pass
+
+class Fireplace(grokcore.site.LocalUtility):
+    interface.implements(IFireplace)
+
+class Painting(grokcore.site.LocalUtility):
+    interface.implements(IPainting)
+
+class Cave(grokcore.site.Site):
+    # we use name_in_container here to prevent multiple registrations
+    # since storing the utilities multiple times under the same name
+    # would raise a DuplicationError
+    grokcore.site.local_utility(Fireplace, name_in_container='fireplace')
+
+class BigCave(Cave):
+    pass
+
+class HollowCave(Cave):
+    grokcore.site.local_utility(Painting)
+
+class VeryHollowCave(HollowCave):
+    grokcore.site.local_utility(Painting, name='great')
+    grokcore.site.local_utility(Painting, name='bad')
+
+# this cave subclasses from Cave twice
+class ScaryCave(VeryHollowCave, Cave):
+    pass
+

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/interfaces.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/interfaces.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/interfaces.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,93 @@
+##############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+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).
+    """
+
+    def __call__(site, utility, provides, name=u'',
+                 name_in_container=None, public=False, setup=None):
+        """Setup an utility.
+        """
+
+
+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):
+    def local_utility(factory, provides=None, name=u'',
+                      setup=None, public=False, name_in_container=None):
+        """Register a local utility.
+
+        factory - the factory that creates the local utility
+        provides - the interface the utility should be looked up with
+        name - the name of the utility
+        setup - a callable that receives the utility as its single argument,
+                it is called after the utility has been created and stored
+        public - if False, the utility will be stored below ++etc++site
+                 if True, the utility will be stored directly in the site.
+                 The site should in this case be a container.
+        name_in_container - the name to use for storing the utility
+        """
+
+    def provides(interface):
+        """Explicitly specify with which interface a component will be
+        looked up."""
+
+
+class IGrokcoreSiteAPI(IGrokcoreComponentAPI, IBaseClasses, IDirectives):
+    """grokcore.site's public API."""
+
+    IApplication = Attribute('The application model interface')
+
+    def getSite():
+        """Get the current site."""
+
+    def getApplication():
+        """Return the nearest enclosing `grok.Application`."""

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,131 @@
+#############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from zope import component
+
+from zope.lifecycleevent.interfaces import IObjectAddedEvent
+from zope.container.interfaces import IContainer,  INameChooser
+
+import martian
+from martian.error import GrokError
+
+import grokcore.component
+import grokcore.site
+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)
+    martian.priority(500)
+    martian.directive(grokcore.site.local_utility, name='infos')
+
+    def execute(self, factory, config, infos, **kw):
+        if not infos:
+            return False
+
+        infos = infos.values()
+        for info in infos:
+            if info.public and not IContainer.implementedBy(factory):
+                raise GrokError(
+                    "Cannot set public to True with grok.local_utility as "
+                    "the site (%r) is not a container." %
+                    factory, factory)
+
+        # Store the list of info objects in their "natural" order on the
+        # site class. They will be picked up by a subscriber doing the
+        # actual registrations in definition order.
+        factory.__grok_utilities_to_install__ = sorted(infos)
+        adapts = (factory, IObjectAddedEvent)
+
+        config.action(
+            discriminator=None,
+            callable=grokcore.component.provideHandler,
+            args=(localUtilityRegistrationSubscriber, adapts),
+            )
+        return True
+
+
+def localUtilityRegistrationSubscriber(site, event):
+    """A subscriber that fires to set up local utilities.
+    """
+    installed = getattr(site, '__grok_utilities_installed__', False)
+    if installed:
+        return
+
+    setupUtility = component.getUtility(
+        grokcore.site.interfaces.IUtilityInstaller)
+    for info in getattr(site.__class__, '__grok_utilities_to_install__', []):
+        setupUtility(site, info.factory(), info.provides, name=info.name,
+                     name_in_container=info.name_in_container,
+                     public=info.public, setup=info.setup)
+
+    # we are done. If this subscriber gets fired again, we therefore
+    # do not register utilities anymore
+    site.__grok_utilities_installed__ = True
+
+
+ at grokcore.component.provider(grokcore.site.interfaces.IUtilityInstaller)
+def setupUtility(site, utility, provides, name=u'',
+                 name_in_container=None, public=False, setup=None):
+    """Set up a utility in a site.
+
+    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()
+
+    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 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=grokcore.component.provideUtility,
+            args=(factory, provides, name),
+            )
+        return True

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.zcml	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.zcml	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:meta="http://namespaces.zope.org/meta"
+    xmlns:grok="http://namespaces.zope.org/grok">
+
+  <include package="grokcore.component" file="meta.zcml" />
+  <grok:grok package=".meta" />
+
+</configure>

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/subscriber.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/subscriber.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/subscriber.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,35 @@
+##############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from zope.lifecycleevent.interfaces import IObjectAddedEvent
+from zope.site import LocalSiteManager
+
+import grokcore.component
+from grokcore.site.components import Site
+
+ at grokcore.component.subscribe(Site, IObjectAddedEvent)
+def addSiteHandler(site, event):
+    """Add a local site manager to a Grok site object upon its creation.
+
+    Grok registers this function so that it gets called each time a
+    `grokcore.site.Site` instance is added to a container.  It creates
+    a local site manager and installs it on the newly created site.
+
+    """
+    sitemanager = LocalSiteManager(site)
+    # LocalSiteManager creates the 'default' folder in its __init__.
+    # It's not needed anymore in new versions of Zope 3, therefore we
+    # remove it
+    del sitemanager['default']
+    site.setSiteManager(sitemanager)

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/testing.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/testing.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/testing.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+##############################################################################
+#
+# Copyright (c) 2007-2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok test helpers
+"""
+from zope.configuration.config import ConfigurationMachine
+from grokcore.component import zcml
+
+def grok(module_name):
+    config = ConfigurationMachine()
+    zcml.do_grok('grokcore.component.meta', config)
+    zcml.do_grok('grokcore.site.meta', config)
+    zcml.do_grok(module_name, config)
+    config.execute_actions()

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# make this directory a package

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/application.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/application.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/application.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -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.
+    """

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/test_grok.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/test_grok.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/test_grok.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,50 @@
+import re
+import unittest
+from pkg_resources import resource_listdir
+from zope.testing import doctest, cleanup, renormalizing
+import zope.component.eventtesting
+
+def setUpZope(test):
+    zope.component.eventtesting.setUp(test)
+
+def cleanUpZope(test):
+    cleanup.cleanUp()
+
+checker = renormalizing.RENormalizing([
+    # str(Exception) has changed from Python 2.4 to 2.5 (due to
+    # Exception now being a new-style class).  This changes the way
+    # exceptions appear in traceback printouts.
+    (re.compile(r"ConfigurationExecutionError: <class '([\w.]+)'>:"),
+                r'ConfigurationExecutionError: \1:'),
+    ])
+
+def suiteFromPackage(name):
+    files = resource_listdir(__name__, name)
+    suite = unittest.TestSuite()
+    for filename in files:
+        if not filename.endswith('.py'):
+            continue
+        if filename.endswith('_fixture.py'):
+            continue
+        if filename == '__init__.py':
+            continue
+
+        dottedname = 'grokcore.site.tests.%s.%s' % (name, filename[:-3])
+        test = doctest.DocTestSuite(dottedname,
+                                    setUp=setUpZope,
+                                    tearDown=cleanUpZope,
+                                    checker=checker,
+                                    optionflags=doctest.ELLIPSIS+
+                                    doctest.NORMALIZE_WHITESPACE)
+
+        suite.addTest(test)
+    return suite
+
+def test_suite():
+    suite = unittest.TestSuite()
+    for name in ['utility', 'application']:
+        suite.addTest(suiteFromPackage(name))
+    return suite
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/__init__.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/__init__.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+"""
+Anything can be registered as a local utility. If it implements a single
+interface, there is no need to specify which interface it provides.
+
+In this test, the utility implements more than one interface, so it cannot be
+registered as a local utility.
+
+  >>> import grokcore.site.tests.utility.local_implementsmany_fixture
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.site.tests.utility.local_implementsmany_fixture.Fireplace'>
+  is implementing more than one interface (use grok.provides to specify
+  which one to use).
+
+"""

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+import grokcore.site
+from zope import interface
+
+class IHome(interface.Interface):
+    pass
+
+class IFireplace(interface.Interface):
+    pass
+
+class Fireplace(object):
+    interface.implements(IHome, IFireplace)
+
+class Cave(grokcore.site.Site):
+    grokcore.site.local_utility(Fireplace)

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+Anything can be registered as a local utility. If it implements a single
+interface, there is no need to specify which interface it provides.
+
+In this test, the utility does not implement any interface, so it cannot be
+registered as a local utility.
+
+  >>> import grokcore.site.tests.utility.local_implementsnone_fixture
+  Traceback (most recent call last):
+    ...
+  GrokError: <class 'grokcore.site.tests.utility.local_implementsnone_fixture.Fireplace'>
+  must implement at least one interface (use grok.implements to specify).
+
+"""

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+  >>> import grokcore.site.tests.utility.local_implementsnone2_fixture
+  Traceback (most recent call last):
+    ...
+  GrokImportError: ("Cannot determine which interface to use for utility
+  registration of
+  <class 'grokcore.site.tests.utility.local_implementsnone2_fixture.Fireplace'>.
+  It implements an interface that is a specialization of an interface
+  implemented by grok.LocalUtility. Specify the interface by either
+  using grok.provides on the utility or passing 'provides' to
+  grok.local_utility.",
+  <class 'grokcore.site.tests.utility.local_implementsnone2_fixture.Fireplace'>)
+
+"""

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,12 @@
+import grokcore.site
+from zope import interface
+import persistent
+
+class ISpecialPersistent(persistent.interfaces.IPersistent):
+    pass
+
+class Fireplace(grokcore.site.LocalUtility):
+    interface.implements(ISpecialPersistent)
+
+class Cave(grokcore.site.Site):
+    grokcore.site.local_utility(Fireplace)

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+import grokcore.site
+
+class Fireplace(object):
+    pass
+
+class Cave(grokcore.site.Site):
+    grokcore.site.local_utility(Fireplace)

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+When you try to register multiple classes with the same (interface, name)
+combination multiple times using grok.local_utility, we expect an error:
+
+  >>> import grokcore.site.tests.utility.multiple_class_fixture
+  Traceback (most recent call last):
+    ...
+  GrokImportError: ("Conflicting local utility registration
+  <class 'grokcore.site.tests.utility.multiple_class_fixture.Fireplace2'>.
+  Local utilities are registered multiple times for interface
+  <InterfaceClass grokcore.site.tests.utility.multiple_class_fixture.IFireplace>
+  and name 'Foo'.",
+  <class 'grokcore.site.tests.utility.multiple_class_fixture.Fireplace2'>)
+"""

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+import grokcore.site
+from zope import interface
+
+class IFireplace(interface.Interface):
+    pass
+
+class Fireplace(grokcore.site.LocalUtility):
+    interface.implements(IFireplace)
+
+class Fireplace2(grokcore.site.LocalUtility):
+    interface.implements(IFireplace)
+    
+class Cave(grokcore.site.Site):
+    grokcore.site.local_utility(Fireplace, name='Foo')
+    grokcore.site.local_utility(Fireplace2, name='Foo')

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+When you call the grok.local_utility directive multiple times specifying
+the same (interface, name) combination, we expect an error:
+
+  >>> import grokcore.site.tests.utility.multiple_directive_fixture
+  Traceback (most recent call last):
+    ...
+  GrokImportError: ("Conflicting local utility registration
+  <class 'grokcore.site.tests.utility.multiple_directive_fixture.Fireplace2'>.
+  Local utilities are registered multiple times for interface
+  <InterfaceClass grokcore.site.tests.utility.multiple_directive_fixture.IFireplace>
+  and name u''.",
+  <class 'grokcore.site.tests.utility.multiple_directive_fixture.Fireplace2'>)
+"""

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive_fixture.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive_fixture.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+import grokcore.site
+from zope import interface
+
+class IFireplace(interface.Interface):
+    pass
+
+class Fireplace(grokcore.site.LocalUtility):
+    interface.implements(IFireplace)
+
+class Fireplace2(grokcore.site.LocalUtility):
+    interface.implements(IFireplace)
+    
+class Cave(grokcore.site.Site):
+    grokcore.site.local_utility(Fireplace, provides=IFireplace)
+    grokcore.site.local_utility(Fireplace2, provides=IFireplace)

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/publicnoncontainer.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/publicnoncontainer.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/publicnoncontainer.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+"""
+You cannot use local_utility with 'public' set to True if the site class
+isn't a container:
+
+  >>> grokcore.site.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: Cannot set public to True with grok.local_utility as the site
+  (<class 'grokcore.site.tests.utility.publicnoncontainer.Cave'>) is not a container.
+
+"""
+import grokcore.site
+
+from zope import interface
+
+class IFireplace(interface.Interface):
+    pass
+
+class Fireplace(grokcore.site.LocalUtility):
+    interface.implements(IFireplace)
+    
+class Cave(grokcore.site.Site):
+    grokcore.site.local_utility(Fireplace, public=True,
+                                name_in_container='fireplace')

Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/util.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/util.py	                        (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/util.py	2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,64 @@
+##############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+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:`grokcore.site.Application`.
+
+    Raises :exc:`ValueError` if no application can be found.
+    """
+    site = getSite()
+    if IApplication.providedBy(site):
+        return site
+    # Another sub-site is within the application. Walk up the object
+    # tree until we get to the an application.
+    obj = site
+    while obj is not None:
+        if IApplication.providedBy(obj):
+            return obj
+        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