[Checkins] SVN: grokcore.permission/ initial import

Christian Klinger cvs-admin at zope.org
Mon Apr 30 12:08:47 UTC 2012


Log message for revision 125434:
  initial import

Changed:
  A   grokcore.permission/
  A   grokcore.permission/trunk/
  A   grokcore.permission/trunk/.mr.developer.cfg
  A   grokcore.permission/trunk/CHANGES.txt
  A   grokcore.permission/trunk/LICENSE.txt
  A   grokcore.permission/trunk/README.txt
  A   grokcore.permission/trunk/bin/
  A   grokcore.permission/trunk/bin/buildout
  A   grokcore.permission/trunk/bin/develop
  A   grokcore.permission/trunk/bin/test
  A   grokcore.permission/trunk/bootstrap.py
  A   grokcore.permission/trunk/buildout.cfg
  A   grokcore.permission/trunk/develop-eggs/
  A   grokcore.permission/trunk/develop-eggs/grokcore.component.egg-link
  A   grokcore.permission/trunk/develop-eggs/grokcore.permission.egg-link
  A   grokcore.permission/trunk/parts/
  A   grokcore.permission/trunk/parts/buildout/
  A   grokcore.permission/trunk/parts/test/
  A   grokcore.permission/trunk/parts/test/site-packages/
  A   grokcore.permission/trunk/parts/test/working-directory/
  A   grokcore.permission/trunk/setup.py
  A   grokcore.permission/trunk/src/
  A   grokcore.permission/trunk/src/grokcore/
  A   grokcore.permission/trunk/src/grokcore/__init__.py
  A   grokcore.permission/trunk/src/grokcore/permission/
  A   grokcore.permission/trunk/src/grokcore/permission/__init__.py
  A   grokcore.permission/trunk/src/grokcore/permission/components.py
  A   grokcore.permission/trunk/src/grokcore/permission/configure.zcml
  A   grokcore.permission/trunk/src/grokcore/permission/directive.py
  A   grokcore.permission/trunk/src/grokcore/permission/ftesting.zcml
  A   grokcore.permission/trunk/src/grokcore/permission/ftests/
  A   grokcore.permission/trunk/src/grokcore/permission/ftests/__init__.py
  A   grokcore.permission/trunk/src/grokcore/permission/ftests/permission/
  A   grokcore.permission/trunk/src/grokcore/permission/ftests/permission/__init__.py
  A   grokcore.permission/trunk/src/grokcore/permission/ftests/permission/roles.py
  A   grokcore.permission/trunk/src/grokcore/permission/ftests/test_grok_functional.py
  A   grokcore.permission/trunk/src/grokcore/permission/interfaces.py
  A   grokcore.permission/trunk/src/grokcore/permission/meta.py
  A   grokcore.permission/trunk/src/grokcore/permission/meta.zcml
  A   grokcore.permission/trunk/src/grokcore/permission/testing.py
  A   grokcore.permission/trunk/src/grokcore/permission/tests/
  A   grokcore.permission/trunk/src/grokcore/permission/tests/__init__.py
  A   grokcore.permission/trunk/src/grokcore/permission/tests/permission/
  A   grokcore.permission/trunk/src/grokcore/permission/tests/permission/__init__.py
  A   grokcore.permission/trunk/src/grokcore/permission/tests/permission/missing_role_name.py
  A   grokcore.permission/trunk/src/grokcore/permission/tests/permission/not_a_permission_class.py
  A   grokcore.permission/trunk/src/grokcore/permission/tests/permission/not_a_permission_class_fixture.py
  A   grokcore.permission/trunk/src/grokcore/permission/tests/permission/permissions.py
  A   grokcore.permission/trunk/src/grokcore/permission/tests/permission/role_i18n.py
  A   grokcore.permission/trunk/src/grokcore/permission/tests/test_grok.py
  A   grokcore.permission/trunk/src/grokcore.component/
  A   grokcore.permission/trunk/src/grokcore.component/CHANGES.txt
  A   grokcore.permission/trunk/src/grokcore.component/COPYRIGHT.txt
  A   grokcore.permission/trunk/src/grokcore.component/CREDITS.txt
  A   grokcore.permission/trunk/src/grokcore.component/INSTALL.txt
  A   grokcore.permission/trunk/src/grokcore.component/LICENSE.txt
  A   grokcore.permission/trunk/src/grokcore.component/README.txt
  A   grokcore.permission/trunk/src/grokcore.component/TODO.txt
  A   grokcore.permission/trunk/src/grokcore.component/bootstrap.py
  A   grokcore.permission/trunk/src/grokcore.component/buildout.cfg
  A   grokcore.permission/trunk/src/grokcore.component/setup.py
  A   grokcore.permission/trunk/src/grokcore.component/src/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/components.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/decorators.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/directive.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/interfaces.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/meta.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/meta.zcml
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/subscription.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/templates/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/testing.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/util.py
  A   grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/zcml.py

-=-
Added: grokcore.permission/trunk/.mr.developer.cfg
===================================================================
--- grokcore.permission/trunk/.mr.developer.cfg	                        (rev 0)
+++ grokcore.permission/trunk/.mr.developer.cfg	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,9 @@
+[develop]
+grokcore.component = true
+
+[buildout]
+args = 'bin/buildout'
+
+[mr.developer]
+rewrites = 
+

Added: grokcore.permission/trunk/CHANGES.txt
===================================================================
--- grokcore.permission/trunk/CHANGES.txt	                        (rev 0)
+++ grokcore.permission/trunk/CHANGES.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/LICENSE.txt
===================================================================
--- grokcore.permission/trunk/LICENSE.txt	                        (rev 0)
+++ grokcore.permission/trunk/LICENSE.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/README.txt
===================================================================
--- grokcore.permission/trunk/README.txt	                        (rev 0)
+++ grokcore.permission/trunk/README.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,7 @@
+===============
+grokcore.xmlrpc
+===============
+
+XML-RPC Views for Grok.
+
+This package provides base classes for XML-RPC Views for Grok.

Added: grokcore.permission/trunk/bin/buildout
===================================================================
--- grokcore.permission/trunk/bin/buildout	                        (rev 0)
+++ grokcore.permission/trunk/bin/buildout	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,13 @@
+#!/Users/christian/work/sprint/grokcore.permission/../bin/python
+
+import sys
+sys.path[0:0] = [
+    '/Users/christian/.buildout/eggs/setuptools-0.6c11-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zc.buildout-1.5.2-py2.6.egg',
+    ]
+
+
+import zc.buildout.buildout
+
+if __name__ == '__main__':
+    zc.buildout.buildout.main()


Property changes on: grokcore.permission/trunk/bin/buildout
___________________________________________________________________
Added: svn:executable
   + 

Added: grokcore.permission/trunk/bin/develop
===================================================================
--- grokcore.permission/trunk/bin/develop	                        (rev 0)
+++ grokcore.permission/trunk/bin/develop	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,15 @@
+#!/Users/christian/work/sprint/grokcore.permission/../bin/python
+
+import sys
+sys.path[0:0] = [
+    '/Users/christian/.buildout/eggs/mr.developer-1.17-py2.6.egg',
+    '/Users/christian/.buildout/eggs/argparse-1.1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zc.buildout-1.5.2-py2.6.egg',
+    '/Users/christian/.buildout/eggs/setuptools-0.6c11-py2.6.egg',
+    ]
+
+
+import mr.developer.develop
+
+if __name__ == '__main__':
+    mr.developer.develop.develop()


Property changes on: grokcore.permission/trunk/bin/develop
___________________________________________________________________
Added: svn:executable
   + 

Added: grokcore.permission/trunk/bin/test
===================================================================
--- grokcore.permission/trunk/bin/test	                        (rev 0)
+++ grokcore.permission/trunk/bin/test	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,75 @@
+#!/Users/christian/work/sprint/grokcore.permission/../bin/python
+
+import sys
+sys.path[0:0] = [
+    '/Users/christian/work/sprint/grokcore.permission/src',
+    '/Users/christian/.buildout/eggs/zope.testrunner-4.0.3-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.interface-3.6.3-py2.6-macosx-10.4-x86_64.egg',
+    '/Users/christian/.buildout/eggs/zope.exceptions-3.6.1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/setuptools-0.6c11-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.login-1.0.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/grokcore.view-2.6.1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.app.wsgi-3.13.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.testing-3.10.2-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.principalregistry-3.7.1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.publisher-3.12.6-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.component-3.10.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/martian-0.14-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.securitypolicy-3.7.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/grokcore.security-1.5-py2.6.egg',
+    '/Users/christian/work/sprint/grokcore.permission/src/grokcore.component/src',
+    '/Users/christian/.buildout/eggs/zope.authentication-3.7.1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.traversing-3.14.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.security-3.8.2-py2.6-macosx-10.4-x86_64.egg',
+    '/Users/christian/.buildout/eggs/zope.ptresource-3.9.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.pagetemplate-3.5.2-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.contentprovider-3.7.2-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.browserresource-3.12.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.browserpage-3.12.2-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.testbrowser-4.0.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.site-3.9.2-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.session-3.9.4-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.lifecycleevent-3.6.2-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.error-3.7.2-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.container-3.12.0-py2.6-macosx-10.4-x86_64.egg',
+    '/Users/christian/.buildout/eggs/zope.configuration-3.7.4-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.event-3.5.0_1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.app.publication-3.13.1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.processlifetime-1.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.app.appsetup-3.15.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/ZODB3-3.10.3-py2.6-macosx-10.4-x86_64.egg',
+    '/Users/christian/.buildout/eggs/ZConfig-2.8.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/WebTest-1.2.3-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.password-3.6.1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.proxy-3.6.1-py2.6-macosx-10.4-x86_64.egg',
+    '/Users/christian/.buildout/eggs/zope.location-3.9.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.i18n-3.7.4-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.contenttype-3.5.3-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.browser-1.3-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.schema-3.7.1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.i18nmessageid-3.5.3-py2.6-macosx-10.4-x86_64.egg',
+    '/Users/christian/.buildout/eggs/zope.annotation-3.5.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.tal-3.5.2-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.tales-3.5.1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/pytz-2011g-py2.6.egg',
+    '/Users/christian/.buildout/eggs/mechanize-0.2.5-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.minmax-1.1.2-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.broken-3.6.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.size-3.4.1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.filerepresentation-3.6.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zope.dottedname-3.4.6-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zdaemon-2.0.4-py2.6.egg',
+    '/Users/christian/.buildout/eggs/zc.lockfile-1.0.0-py2.6.egg',
+    '/Users/christian/.buildout/eggs/transaction-1.1.1-py2.6.egg',
+    '/Users/christian/.buildout/eggs/WebOb-1.0.4-py2.6.egg',
+    '/Users/christian/.buildout/eggs/RestrictedPython-3.6.0-py2.6.egg',
+    ]
+
+
+import zope.testrunner
+
+if __name__ == '__main__':
+    zope.testrunner.run((['--tests-pattern', '^f?tests$', '-v', '--auto-color']) + [
+        '--test-path', '/Users/christian/work/sprint/grokcore.permission/src',
+        '--test-path', '/Users/christian/work/sprint/grokcore.permission/src',
+        ])


Property changes on: grokcore.permission/trunk/bin/test
___________________________________________________________________
Added: svn:executable
   + 

Added: grokcore.permission/trunk/bootstrap.py
===================================================================
--- grokcore.permission/trunk/bootstrap.py	                        (rev 0)
+++ grokcore.permission/trunk/bootstrap.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/buildout.cfg
===================================================================
--- grokcore.permission/trunk/buildout.cfg	                        (rev 0)
+++ grokcore.permission/trunk/buildout.cfg	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,22 @@
+[buildout]
+extends = http://svn.zope.org/repos/main/groktoolkit/trunk/grok.cfg
+develop = .
+parts =
+  test
+extensions =
+  buildout.dumppickedversions
+  mr.developer
+
+[sources]
+grokcore.component = svn svn+ssh://svn.zope.org/repos/main/grokcore.component/trunk
+
+
+[versions]
+grokcore.xmlrpc =
+
+[test]
+recipe = zc.recipe.testrunner
+eggs =
+    grokcore.permission
+    grokcore.permission[test]
+defaults = ['--tests-pattern', '^f?tests$', '-v', '--auto-color']

Added: grokcore.permission/trunk/develop-eggs/grokcore.component.egg-link
===================================================================
--- grokcore.permission/trunk/develop-eggs/grokcore.component.egg-link	                        (rev 0)
+++ grokcore.permission/trunk/develop-eggs/grokcore.component.egg-link	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,2 @@
+/Users/christian/work/sprint/grokcore.permission/src/grokcore.component/src
+../
\ No newline at end of file

Added: grokcore.permission/trunk/develop-eggs/grokcore.permission.egg-link
===================================================================
--- grokcore.permission/trunk/develop-eggs/grokcore.permission.egg-link	                        (rev 0)
+++ grokcore.permission/trunk/develop-eggs/grokcore.permission.egg-link	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,2 @@
+/Users/christian/work/sprint/grokcore.permission/src
+../
\ No newline at end of file

Added: grokcore.permission/trunk/setup.py
===================================================================
--- grokcore.permission/trunk/setup.py	                        (rev 0)
+++ grokcore.permission/trunk/setup.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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')
+    + '\n' +
+    'Download\n'
+    '********\n'
+    )
+
+tests_require = [
+    'zope.testing',
+    'zope.app.wsgi',
+    'grokcore.view',
+    'zope.login',
+    ]
+
+setup(
+    name='grokcore.permission',
+    version='1.2dev',
+    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='Permission Role Components 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',
+        'grokcore.component',
+        'grokcore.security',
+        'zope.securitypolicy',
+        'martian',
+        'zope.component',
+        'zope.interface',
+        'zope.publisher',
+        'zope.principalregistry',
+        ],
+    tests_require=tests_require,
+    extras_require={'test': tests_require},
+)

Added: grokcore.permission/trunk/src/grokcore/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore/permission/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission.components import Role
+from grokcore.permission.directive import permissions
\ No newline at end of file

Added: grokcore.permission/trunk/src/grokcore/permission/components.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/components.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/components.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,37 @@
+##############################################################################
+#
+# 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 zope.securitypolicy.role import Role as securitypolicy_Role
+
+
+class Role(securitypolicy_Role):
+    """Base class for roles in Grok applications.
+
+    A role is a description of a class of users that gives them a
+    machine-readable name, a human-readable title, and a set of
+    permissions which users belong to that role should possess::
+
+        class Editor(grok.Role):
+            grok.name('news.Editor')
+            grok.title('Editor')
+            grok.permissions('news.EditArticle', 'news.PublishArticle')
+
+    """

Added: grokcore.permission/trunk/src/grokcore/permission/configure.zcml
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/configure.zcml	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/configure.zcml	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,8 @@
+<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" />
+
+</configure>

Added: grokcore.permission/trunk/src/grokcore/permission/directive.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/directive.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/directive.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.
+#
+##############################################################################
+"""Grok directives.
+"""
+
+import martian
+import martian.util
+import grokcore.component
+from martian.error import GrokImportError
+from grokcore.security import Permission
+
+
+class permissions(martian.Directive):
+    """The `grokcore.permission.permissions()` directive.
+
+    This directive is used inside of a `grok.Role` subclass to list the
+    permissions which each member of the role should always possess.
+    Note that permissions should be passed as strings, and that several
+    permissions they can simply be supplied as multiple arguments; there
+    is no need to place them inside of a tuple or list::
+
+        class MyRole(grokcore.permission.Role):
+            grokcore.permission.permissions('page.CreatePage', 'page.EditPage')
+            ...
+
+    """
+    scope = martian.CLASS
+    store = martian.ONCE
+    default = []
+
+    def validate(self, *values):
+        for value in values:
+            if martian.util.check_subclass(value, Permission):
+                continue
+            if martian.util.not_unicode_or_ascii(value):
+                raise GrokImportError(
+                    "You can only pass unicode values, ASCII values, or "
+                    "subclasses of grokcore.security.Permission to the '%s'"
+                    " directive."
+                    % self.name)
+
+    def factory(self, *values):
+        permission_ids = []
+        for value in values:
+            if martian.util.check_subclass(value, Permission):
+                permission_ids.append(grokcore.component.name.bind().get(value))
+            else:
+                permission_ids.append(value)
+        return permission_ids

Added: grokcore.permission/trunk/src/grokcore/permission/ftesting.zcml
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/ftesting.zcml	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/ftesting.zcml	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,17 @@
+<configure
+  xmlns="http://namespaces.zope.org/zope"
+  xmlns:grok="http://namespaces.zope.org/grok"
+  xmlns:browser="http://namespaces.zope.org/browser"
+  i18n_domain="grokcore.permission"
+  package="grokcore.permission">
+
+  <!--
+  <include package="zope.errorview" file="http.zcml" />
+  -->
+  <include package="grokcore.view" file="ftesting.zcml" />
+  <include package="grokcore.permission" file="meta.zcml" />
+  <include package="grokcore.view" file="publication_security.zcml" />
+
+  <grok:grok package=".ftests" />
+
+</configure>

Added: grokcore.permission/trunk/src/grokcore/permission/ftests/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/ftests/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/ftests/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+# i am a package

Added: grokcore.permission/trunk/src/grokcore/permission/ftests/permission/roles.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/ftests/permission/roles.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/ftests/permission/roles.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,100 @@
+"""
+Viewing a protected view with insufficient privileges will yield
+Unauthorized:
+
+  >>> from zope.app.wsgi.testlayer import Browser
+  >>> browser = Browser()
+
+  >>> browser.open("http://localhost/@@cavepainting")
+  Traceback (most recent call last):
+  HTTPError: HTTP Error 401: Unauthorized
+
+  >>> browser.open("http://localhost/@@editcavepainting")
+  Traceback (most recent call last):
+  HTTPError: HTTP Error 401: Unauthorized
+
+  >>> browser.open("http://localhost/@@erasecavepainting")
+  Traceback (most recent call last):
+  HTTPError: HTTP Error 401: Unauthorized
+
+Let's now grant anonymous the PaintingOwner role locally (so that we
+don't have to modify the global setup).  Then we can access the views
+just fine:
+
+  >>> from zope.securitypolicy.interfaces import IPrincipalRoleManager
+  >>> root = getRootFolder()
+  >>> IPrincipalRoleManager(root).assignRoleToPrincipal(
+  ...    'paint.PaintingOwner', 'zope.anybody')
+
+  >>> browser.open("http://localhost/@@cavepainting")
+  >>> print browser.contents
+  What a beautiful painting.
+
+  >>> browser.open("http://localhost/@@editcavepainting")
+  >>> print browser.contents
+  Let's make it even prettier.
+
+  >>> browser.open("http://localhost/@@erasecavepainting")
+  >>> print browser.contents
+  Oops, mistake, let's erase it.
+
+  >>> browser.open("http://localhost/@@approvecavepainting")
+  Traceback (most recent call last):
+  HTTPError: HTTP Error 401: Unauthorized
+"""
+
+import grokcore.permission
+import grokcore.security
+import grokcore.view
+import grokcore.component as grok
+import zope.interface
+
+class ViewPermission(grokcore.security.Permission):
+    grok.name('paint.ViewPainting')
+
+class EditPermission(grokcore.security.Permission):
+    grok.name('paint.EditPainting')
+
+class ErasePermission(grokcore.security.Permission):
+    grok.name('paint.ErasePainting')
+
+class ApprovePermission(grokcore.security.Permission):
+    grok.name('paint.ApprovePainting')
+
+class PaintingOwner(grokcore.permission.Role):
+    grok.name('paint.PaintingOwner')
+    grok.title('Painting Owner')
+    grokcore.permission.permissions(
+        'paint.ViewPainting', 'paint.EditPainting', 'paint.ErasePainting')
+
+class CavePainting(grokcore.view.View):
+
+    grok.context(zope.interface.Interface)
+    grokcore.security.require(ViewPermission)
+
+    def render(self):
+        return 'What a beautiful painting.'
+
+class EditCavePainting(grokcore.view.View):
+
+    grok.context(zope.interface.Interface)
+    grokcore.security.require(EditPermission)
+
+    def render(self):
+        return 'Let\'s make it even prettier.'
+
+class EraseCavePainting(grokcore.view.View):
+
+    grok.context(zope.interface.Interface)
+    grokcore.security.require(ErasePermission)
+
+    def render(self):
+        return 'Oops, mistake, let\'s erase it.'
+
+class ApproveCavePainting(grokcore.view.View):
+
+    grok.context(zope.interface.Interface)
+    grokcore.security.require(ApprovePermission)
+
+    def render(self):
+        return 'Painting owners cannot approve their paintings.'

Added: grokcore.permission/trunk/src/grokcore/permission/ftests/test_grok_functional.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/ftests/test_grok_functional.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/ftests/test_grok_functional.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,50 @@
+import re
+import doctest
+import unittest
+import grokcore.permission
+
+from pkg_resources import resource_listdir
+from zope.testing import renormalizing
+from zope.app.wsgi.testlayer import BrowserLayer, http
+
+FunctionalLayer = BrowserLayer(grokcore.permission)
+
+checker = renormalizing.RENormalizing([
+    # Accommodate to exception wrapping in newer versions of mechanize
+    (re.compile(r'httperror_seek_wrapper:', re.M), 'HTTPError:'),
+    ])
+
+
+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.permission.ftests.%s.%s' % (name, filename[:-3])
+        test = doctest.DocTestSuite(
+            dottedname,
+            checker=checker,
+            extraglobs=dict(http=http,
+                            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 ['permission']:
+        suite.addTest(suiteFromPackage(name))
+    return suite
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')

Added: grokcore.permission/trunk/src/grokcore/permission/interfaces.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/interfaces.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/interfaces.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,20 @@
+##############################################################################
+#
+# 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
+"""
+
+# Expose interfaces from grokcore.* packages as well:
+import grokcore.component.interfaces
+import grokcore.security.interfaces
+import grokcore.view.interfaces

Added: grokcore.permission/trunk/src/grokcore/permission/meta.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/meta.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/meta.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,85 @@
+#############################################################################
+#
+# 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.
+
+"""
+from zope.i18nmessageid import Message
+
+import martian
+import grokcore.component
+import grokcore.component.util
+import grokcore.component as grok
+
+
+from martian.error import GrokError
+from grokcore.security.meta import PermissionGrokker
+from zope.securitypolicy.rolepermission import rolePermissionManager
+from grokcore.permission.components import Role
+from grokcore.permission.directive import permissions
+from zope.securitypolicy.interfaces import IRole
+
+
+def default_fallback_to_name(factory, module, name, **data):
+    return name
+
+
+class RoleGrokker(martian.ClassGrokker):
+    """Grokker for components subclassed from `grok.Role`.
+
+    Each role is registered as a global utility providing the service
+    `IRole` under its own particular name, and then granted every
+    permission named in its `grok.permission()` directive.
+
+    """
+    martian.component(Role)
+    martian.priority(martian.priority.bind().get(PermissionGrokker()) - 1)
+    martian.directive(grok.name)
+    martian.directive(grok.title, get_default=default_fallback_to_name)
+    martian.directive(grok.description)
+    martian.directive(permissions)
+
+    def execute(self, factory, config, name, title, description,
+                permissions, **kw):
+        if not name:
+            raise GrokError(
+                "A role needs to have a dotted name for its id. Use "
+                "grok.name to specify one.", factory)
+        # We can safely convert to unicode, since the directives makes sure
+        # it is either unicode already or ASCII.
+        if not isinstance(title, Message):
+            title = unicode(title)
+        if not isinstance(description, Message):
+            description = unicode(description)
+        role = factory(unicode(name), title, description)
+
+        config.action(
+            discriminator=('utility', IRole, name),
+            callable=grokcore.component.util.provideUtility,
+            args=(role, IRole, name),
+            )
+
+        for permission in permissions:
+            config.action(
+                discriminator=('grantPermissionToRole', permission, name),
+                callable=rolePermissionManager.grantPermissionToRole,
+                args=(permission, name),
+                )
+        return True
\ No newline at end of file

Added: grokcore.permission/trunk/src/grokcore/permission/meta.zcml
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/meta.zcml	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/meta.zcml	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,14 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:meta="http://namespaces.zope.org/meta"
+    xmlns:grok="http://namespaces.zope.org/grok">
+
+
+  <!-- Load the grokkers -->
+  <include package="grokcore.component" file="meta.zcml" />
+  <include package="grokcore.security" file="meta.zcml" />
+  <include package="grokcore.view" file="meta.zcml" />
+
+  <grok:grok package=".meta" />
+
+</configure>

Added: grokcore.permission/trunk/src/grokcore/permission/testing.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/testing.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/testing.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,28 @@
+##############################################################################
+#
+# 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
+"""
+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.security.meta', config)
+    zcml.do_grok('grokcore.view.meta', config)
+    zcml.do_grok('grokcore.view.templatereg', config)
+    zcml.do_grok('grokcore.permission', config)
+    zcml.do_grok(module_name, config)
+    config.execute_actions()

Added: grokcore.permission/trunk/src/grokcore/permission/tests/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/tests/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/tests/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+# i am a package

Added: grokcore.permission/trunk/src/grokcore/permission/tests/permission/missing_role_name.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/tests/permission/missing_role_name.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/tests/permission/missing_role_name.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,15 @@
+"""
+A role has to have a name to be defined.
+
+  >>> grokcore.permission.testing.grok(__name__)
+  Traceback (most recent call last):
+  GrokError: A role needs to have a dotted name for its id.
+  Use grok.name to specify one.
+"""
+
+import zope.interface
+import grokcore.permission
+import grokcore.permission.testing
+
+class MissingName(grokcore.permission.components.Role):
+    pass

Added: grokcore.permission/trunk/src/grokcore/permission/tests/permission/not_a_permission_class.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/tests/permission/not_a_permission_class.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/tests/permission/not_a_permission_class.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,13 @@
+"""
+The permissions() directive only accepts permission ids or permission classes:
+
+  >>> import grokcore.permission.testing 
+  >>>
+  >>> grokcore.permission.testing.grok(
+  ...     'grokcore.permission.tests.permission.not_a_permission_class_fixture')
+  Traceback (most recent call last):
+  ...
+  GrokImportError: You can only pass unicode values, ASCII values, or
+  subclasses of grokcore.security.Permission to the 'permissions' directive.
+
+"""

Added: grokcore.permission/trunk/src/grokcore/permission/tests/permission/not_a_permission_class_fixture.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/tests/permission/not_a_permission_class_fixture.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/tests/permission/not_a_permission_class_fixture.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,9 @@
+import grokcore.component as grok
+import grokcore.permission
+
+class NotAPermissionSubclass(object):
+    grok.name('not really a permission')
+
+class MyRole(grokcore.permission.Role):
+    grok.name('MyRole')
+    grokcore.permission.permissions(NotAPermissionSubclass)

Added: grokcore.permission/trunk/src/grokcore/permission/tests/permission/permissions.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/tests/permission/permissions.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/tests/permission/permissions.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,35 @@
+"""
+A Role component optionally defines what permission it comprises.
+
+The grok.permissions() directive is used to specify the set of permissions
+that are aggregated in the particular Role. The permissions can be referenced
+by "name" or by class.
+
+  >>> grokcore.permission.testing.grok(__name__)
+"""
+
+import grokcore.component as grok
+import grokcore.permission.testing
+from grokcore.permission import permissions, Role
+from grokcore.security import Permission
+import zope.interface
+
+class FirstPermission(Permission):
+    grok.name('first permission')
+
+class SecondPermission(Permission):
+    grok.name('second permission')
+
+class RoleComprisingTwoPermissionsByName(Role):
+    grok.name('ByName')
+    permissions(
+        'first permission',
+        'second permission'
+        )
+
+class RoleComprisingTwoPermissionsByClass(Role):
+    grok.name('ByClass')
+    permissions(
+        FirstPermission,
+        SecondPermission
+        )

Added: grokcore.permission/trunk/src/grokcore/permission/tests/permission/role_i18n.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/tests/permission/role_i18n.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/tests/permission/role_i18n.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,78 @@
+"""
+A Role component have a title and description, that can be internationalized.
+
+Let's grok this package and check we still have a Message object for the
+internationalized title and description of the defined roles.
+
+  >>> grokcore.permission.testing.grok(__name__)
+  >>> from zope.securitypolicy.interfaces import IRole
+  >>> from zope.component import getUtility
+  >>> from zope.i18nmessageid import Message
+
+A grok.Role without any internationalization.
+The id, title and description should be unicode::
+
+  >>> role = getUtility(IRole, name="RoleWithoutI18n")
+  >>> role.id
+  u'RoleWithoutI18n'
+  >>> role.title
+  u'RoleWithoutI18n'
+  >>> role.description
+  u'My role without i18n'
+  >>>
+  >>> isinstance(role.id, Message)
+  False
+  >>> isinstance(role.title, Message)
+  False
+  >>> isinstance(role.description, Message)
+  False
+
+A grok.Role registered with the name and description directives only, both
+internationalized.
+The id is taken from the name directive and should not be a Message object.
+The title is taken from the name directive because the title directive
+is not used.
+::
+
+  >>> role = getUtility(IRole, name="RoleWithI18n")
+  >>> isinstance(role.id, Message)
+  False
+  >>> isinstance(role.title, Message)
+  True
+  >>> isinstance(role.description, Message)
+  True
+
+A grok.Role registered with name, title and description directives::
+
+  >>> role = getUtility(IRole, name="RoleWithI18nTitle")
+  >>> isinstance(role.id, Message)
+  False
+  >>> isinstance(role.title, Message)
+  True
+  >>> isinstance(role.description, Message)
+  True
+"""
+
+import grokcore.component as grok
+import grokcore.permission
+
+from grokcore.permission import Role
+from zope.i18nmessageid import MessageFactory
+
+_ = MessageFactory("testi18n")
+
+
+class RoleWithoutI18n(Role):
+    grok.name('RoleWithoutI18n')
+    grok.description('My role without i18n')
+
+
+class RoleWithI18n(Role):
+    grok.name(_('RoleWithI18n'))
+    grok.description(_(u'My role with i18n'))
+
+
+class RoleWithI18nTitle(Role):
+    grok.name('RoleWithI18nTitle')
+    grok.title(_('RoleWithI18n'))
+    grok.description(_(u'My role with i18n'))

Added: grokcore.permission/trunk/src/grokcore/permission/tests/test_grok.py
===================================================================
--- grokcore.permission/trunk/src/grokcore/permission/tests/test_grok.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore/permission/tests/test_grok.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,49 @@
+import re
+import unittest
+from pkg_resources import resource_listdir
+from zope.testing import doctest, cleanup, renormalizing
+
+
+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
+        print filename
+        dottedname = 'grokcore.permission.tests.%s.%s' % (name, filename[:-3])
+        test = doctest.DocTestSuite(dottedname,
+                                    tearDown=cleanUpZope,
+                                    checker=checker,
+                                    optionflags=doctest.ELLIPSIS +
+                                    doctest.NORMALIZE_WHITESPACE)
+
+        suite.addTest(test)
+    return suite
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    for name in ['permission']:
+        suite.addTest(suiteFromPackage(name))
+    return suite
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')

Added: grokcore.permission/trunk/src/grokcore.component/CHANGES.txt
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/CHANGES.txt	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/CHANGES.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,205 @@
+Changes
+=======
+
+2.5 (unreleased)
+----------------
+
+- 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.permission/trunk/src/grokcore.component/COPYRIGHT.txt
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/COPYRIGHT.txt	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/COPYRIGHT.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+Zope Foundation and Contributors
\ No newline at end of file

Added: grokcore.permission/trunk/src/grokcore.component/CREDITS.txt
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/CREDITS.txt	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/CREDITS.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/INSTALL.txt
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/INSTALL.txt	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/INSTALL.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/LICENSE.txt
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/LICENSE.txt	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/LICENSE.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/README.txt
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/README.txt	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/README.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/TODO.txt
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/TODO.txt	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/TODO.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/bootstrap.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/bootstrap.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/bootstrap.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/buildout.cfg
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/buildout.cfg	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/buildout.cfg	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/setup.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/setup.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/setup.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,52 @@
+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},
+    entry_points = """
+        [grok.api]
+        grokcore.component = grokcore.component.interfaces:IGrokcoreComponentAPI
+    """
+)

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,47 @@
+##############################################################################
+#
+# 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, GlobalUtility, MultiAdapter, Context, Subscription,
+    MultiSubscription)
+
+from grokcore.component.directive import (
+    context, description, direct, name, order, path, provides, title,
+    global_utility, global_adapter, order)
+
+from grokcore.component.decorators import (
+    subscribe, adapter, implementer, provider)
+
+from grokcore.component.subscription import (
+    querySubscriptions, queryMultiSubscriptions,
+    queryOrderedSubscriptions, queryOrderedMultiSubscriptions)
+
+# 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.permission/trunk/src/grokcore.component/src/grokcore/component/components.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/components.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/components.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/decorators.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/decorators.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/decorators.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/directive.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/directive.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/directive.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/interfaces.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/interfaces.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/interfaces.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,207 @@
+##############################################################################
+#
+# 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):
+
+    ClassGrokker = Attribute("Base class to define a class grokker.")
+    InstanceGrokker = Attribute("Base class to define an instance grokker.")
+    GlobalGrokker = Attribute("Base class to define a module grokker.")
+
+    Context = Attribute("Base class for automatically associated contexts.")
+
+    Adapter = Attribute("Base class for adapters.")
+    MultiAdapter = Attribute("Base class for multi-adapters.")
+    GlobalUtility = Attribute("Base class for global utilities.")
+    Subscription = Attribute("Base class for subscription adapters.")
+    MultiSubscription = Attribute(
+        "Base class for subscription mult-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."""
+
+    # This should probably move to martian at some point.
+
+    ClassGrokker = Attribute("Grokker for classes.")
+    InstanceGrokker = Attribute("Grokker for instances.")
+    GlobalGrokker = Attribute("Grokker that's invoked for a module.")
+
+
+class IGrokcoreComponentAPI(IBaseClasses, IDirectives, IDecorators,
+                            IGrokErrors, IMartianAPI):
+    """grokcore.component's public API."""
+
+    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.")

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/meta.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/meta.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/meta.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,244 @@
+#############################################################################
+#
+# 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
+from grokcore.component import util
+
+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=util.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=util.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=util.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=util.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=util.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=util.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=util.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=util.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=util.provideHandler,
+                    args=(factory, subscribed))
+            else:
+                config.action(
+                    discriminator=None,
+                    callable=util.provideSubscriptionAdapter,
+                    args=(factory, subscribed, provides))
+
+            for iface in subscribed:
+                config.action(
+                    discriminator=None,
+                    callable=util.provideInterface,
+                    args=('', iface))
+        return True

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/meta.zcml
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/meta.zcml	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/meta.zcml	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/subscription.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/subscription.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/subscription.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/testing.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/testing.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/testing.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+# make this directory a package

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,4 @@
+import grokcore.component as grok
+
+class Foo(object):
+    grok.name('too', 'many', 'arguments')

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,5 @@
+import grokcore.component as grok
+
+ at grok.subscribe()
+def subscriber():
+    pass

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,4 @@
+from grokcore.component.tests.grokker.continue_scanning import Alpha, Beta
+
+class AlphaBetaSub(Alpha, Beta):
+    pass

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+# fixture package
\ No newline at end of file

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,4 @@
+import grokcore.component as grok
+
+class Alpha(object):
+    grok.baseclass()

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,4 @@
+from component import Alpha
+
+class AlphaSub(Alpha):
+    pass
\ No newline at end of file

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+#

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+#

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,42 @@
+"""
+If the grok.order directive is present with arguments, sorting will be
+done by the order specified.
+
+  >>> from grokcore.component.util 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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.util 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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.util 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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.util 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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.util 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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.util 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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1 @@
+# this is a package

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -0,0 +1,5 @@
+"""
+This should fail:
+"""
+import grokcore.component as grok
+grok.name('viewname')

Added: grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/util.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/util.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/util.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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.permission/trunk/src/grokcore.component/src/grokcore/component/zcml.py
===================================================================
--- grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/zcml.py	                        (rev 0)
+++ grokcore.permission/trunk/src/grokcore.component/src/grokcore/component/zcml.py	2012-04-30 12:08:43 UTC (rev 125434)
@@ -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)



More information about the checkins mailing list