[Checkins] SVN: grokcore.registries/ inital import
Christian Klinger
cvs-admin at zope.org
Wed May 2 09:49:07 UTC 2012
Log message for revision 125599:
inital import
Changed:
A grokcore.registries/
A grokcore.registries/trunk/
A grokcore.registries/trunk/.mr.developer.cfg
A grokcore.registries/trunk/CHANGES.txt
A grokcore.registries/trunk/LICENSE.txt
A grokcore.registries/trunk/README.txt
A grokcore.registries/trunk/bootstrap.py
A grokcore.registries/trunk/buildout.cfg
A grokcore.registries/trunk/setup.py
A grokcore.registries/trunk/src/
A grokcore.registries/trunk/src/grokcore/
A grokcore.registries/trunk/src/grokcore/__init__.py
A grokcore.registries/trunk/src/grokcore/registries/
A grokcore.registries/trunk/src/grokcore/registries/README.txt
A grokcore.registries/trunk/src/grokcore/registries/__init__.py
A grokcore.registries/trunk/src/grokcore/registries/components.py
A grokcore.registries/trunk/src/grokcore/registries/configure.zcml
A grokcore.registries/trunk/src/grokcore/registries/ftesting.zcml
A grokcore.registries/trunk/src/grokcore/registries/ftests/
A grokcore.registries/trunk/src/grokcore/registries/ftests/__init__.py
A grokcore.registries/trunk/src/grokcore/registries/ftests/registries/
A grokcore.registries/trunk/src/grokcore/registries/ftests/registries/__init__.py
A grokcore.registries/trunk/src/grokcore/registries/ftests/registries/basic.py
A grokcore.registries/trunk/src/grokcore/registries/ftests/registries/creation.py
A grokcore.registries/trunk/src/grokcore/registries/ftests/registries/grok_integration.py
A grokcore.registries/trunk/src/grokcore/registries/ftests/registries/utils.py
A grokcore.registries/trunk/src/grokcore/registries/ftests/test_grok_functional.py
A grokcore.registries/trunk/src/grokcore/registries/interfaces.py
A grokcore.registries/trunk/src/grokcore/registries/meta.py
A grokcore.registries/trunk/src/grokcore/registries/meta.zcml
A grokcore.registries/trunk/src/grokcore/registries/tests/
A grokcore.registries/trunk/src/grokcore/registries/tests/__init__.py
A grokcore.registries/trunk/src/grokcore/registries/tests/registries/
A grokcore.registries/trunk/src/grokcore/registries/tests/registries/__init__.py
A grokcore.registries/trunk/src/grokcore/registries/tests/registries/base.py
A grokcore.registries/trunk/src/grokcore/registries/tests/registries/global.py
A grokcore.registries/trunk/src/grokcore/registries/tests/registries/interfaces.py
A grokcore.registries/trunk/src/grokcore/registries/tests/registries/local.py
A grokcore.registries/trunk/src/grokcore/registries/tests/test_doc.py
A grokcore.registries/trunk/src/grokcore/registries/utils.py
A grokcore.registries/trunk/src/grokcore.component/
A grokcore.registries/trunk/src/grokcore.component/CHANGES.txt
A grokcore.registries/trunk/src/grokcore.component/COPYRIGHT.txt
A grokcore.registries/trunk/src/grokcore.component/CREDITS.txt
A grokcore.registries/trunk/src/grokcore.component/INSTALL.txt
A grokcore.registries/trunk/src/grokcore.component/LICENSE.txt
A grokcore.registries/trunk/src/grokcore.component/README.txt
A grokcore.registries/trunk/src/grokcore.component/TODO.txt
A grokcore.registries/trunk/src/grokcore.component/bootstrap.py
A grokcore.registries/trunk/src/grokcore.component/buildout.cfg
A grokcore.registries/trunk/src/grokcore.component/setup.py
A grokcore.registries/trunk/src/grokcore.component/src/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/components.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/decorators.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/directive.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/interfaces.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.zcml
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/subscription.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/testing.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/util.py
A grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/zcml.py
A grokcore.registries/trunk/src/grokcore.site/
A grokcore.registries/trunk/src/grokcore.site/CHANGES.txt
A grokcore.registries/trunk/src/grokcore.site/COPYRIGHT.txt
A grokcore.registries/trunk/src/grokcore.site/LICENSE.txt
A grokcore.registries/trunk/src/grokcore.site/README.txt
A grokcore.registries/trunk/src/grokcore.site/bootstrap.py
A grokcore.registries/trunk/src/grokcore.site/buildout.cfg
A grokcore.registries/trunk/src/grokcore.site/setup.py
A grokcore.registries/trunk/src/grokcore.site/src/
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/__init__.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/__init__.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/components.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/configure.zcml
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/directive.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftesting.zcml
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/__init__.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/__init__.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/application.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/__init__.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/site.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/test_grok_functional.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/__init__.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local_override.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/public.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/subclass.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/interfaces.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.zcml
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/subscriber.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/testing.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/__init__.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/__init__.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/application.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/test_grok.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/__init__.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany_fixture.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2_fixture.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone_fixture.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class_fixture.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive_fixture.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/publicnoncontainer.py
A grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/util.py
-=-
Added: grokcore.registries/trunk/.mr.developer.cfg
===================================================================
--- grokcore.registries/trunk/.mr.developer.cfg (rev 0)
+++ grokcore.registries/trunk/.mr.developer.cfg 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,10 @@
+[buildout]
+args = 'bin/buildout'
+
+[develop]
+grokcore.site = true
+grokcore.component = true
+
+[mr.developer]
+rewrites =
+
Added: grokcore.registries/trunk/CHANGES.txt
===================================================================
--- grokcore.registries/trunk/CHANGES.txt (rev 0)
+++ grokcore.registries/trunk/CHANGES.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,21 @@
+=======
+Changes
+=======
+
+1.2 (unreleased)
+================
+
+- Nothing changed yet.
+
+
+1.1 (2011-01-20)
+================
+
+- Use zope.errorview for the functional tests. This lifts the dependency on
+ zope.app.http.
+
+1.0 (2011-01-03)
+================
+
+- Factor out form grok base package
+
Added: grokcore.registries/trunk/LICENSE.txt
===================================================================
--- grokcore.registries/trunk/LICENSE.txt (rev 0)
+++ grokcore.registries/trunk/LICENSE.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,44 @@
+Zope Public License (ZPL) Version 2.1
+
+A copyright notice accompanies this license document that identifies the
+copyright holders.
+
+This license has been certified as open source. It has also been designated as
+GPL compatible by the Free Software Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions in source code must retain the accompanying copyright
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying copyright
+notice, this list of conditions, and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to endorse or promote
+products derived from this software without prior written permission from the
+copyright holders.
+
+4. The right to distribute this software or to use it for any purpose does not
+give you the right to use Servicemarks (sm) or Trademarks (tm) of the
+copyright
+holders. Use of them is covered by separate agreement with the copyright
+holders.
+
+5. If any files are modified, you must cause the modified files to carry
+prominent notices stating that you changed the files and the date of any
+change.
+
+Disclaimer
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Added: grokcore.registries/trunk/README.txt
===================================================================
--- grokcore.registries/trunk/README.txt (rev 0)
+++ grokcore.registries/trunk/README.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+===============
+grokcore.xmlrpc
+===============
+
+XML-RPC Views for Grok.
+
+This package provides base classes for XML-RPC Views for Grok.
Added: grokcore.registries/trunk/bootstrap.py
===================================================================
--- grokcore.registries/trunk/bootstrap.py (rev 0)
+++ grokcore.registries/trunk/bootstrap.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,260 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
+from optparse import OptionParser
+
+if sys.platform == 'win32':
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ quote = str
+
+# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
+stdout, stderr = subprocess.Popen(
+ [sys.executable, '-Sc',
+ 'try:\n'
+ ' import ConfigParser\n'
+ 'except ImportError:\n'
+ ' print 1\n'
+ 'else:\n'
+ ' print 0\n'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+has_broken_dash_S = bool(int(stdout.strip()))
+
+# In order to be more robust in the face of system Pythons, we want to
+# run without site-packages loaded. This is somewhat tricky, in
+# particular because Python 2.6's distutils imports site, so starting
+# with the -S flag is not sufficient. However, we'll start with that:
+if not has_broken_dash_S and 'site' in sys.modules:
+ # We will restart with python -S.
+ args = sys.argv[:]
+ args[0:0] = [sys.executable, '-S']
+ args = map(quote, args)
+ os.execv(sys.executable, args)
+# Now we are running with -S. We'll get the clean sys.path, import site
+# because distutils will do it later, and then reset the path and clean
+# out any namespace packages from site-packages that might have been
+# loaded by .pth files.
+clean_path = sys.path[:]
+import site
+sys.path[:] = clean_path
+for k, v in sys.modules.items():
+ if k in ('setuptools', 'pkg_resources') or (
+ hasattr(v, '__path__') and
+ len(v.__path__)==1 and
+ not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
+ # This is a namespace package. Remove it.
+ sys.modules.pop(k)
+
+is_jython = sys.platform.startswith('java')
+
+setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
+distribute_source = 'http://python-distribute.org/distribute_setup.py'
+
+# parsing arguments
+def normalize_to_url(option, opt_str, value, parser):
+ if value:
+ if '://' not in value: # It doesn't smell like a URL.
+ value = 'file://%s' % (
+ urllib.pathname2url(
+ os.path.abspath(os.path.expanduser(value))),)
+ if opt_str == '--download-base' and not value.endswith('/'):
+ # Download base needs a trailing slash to make the world happy.
+ value += '/'
+ else:
+ value = None
+ name = opt_str[2:].replace('-', '_')
+ setattr(parser.values, name, value)
+
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
+
+Bootstraps a buildout-based project.
+
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", dest="version",
+ help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+ action="store_true", dest="use_distribute", default=False,
+ help="Use Distribute rather than Setuptools.")
+parser.add_option("--setup-source", action="callback", dest="setup_source",
+ callback=normalize_to_url, nargs=1, type="string",
+ help=("Specify a URL or file location for the setup file. "
+ "If you use Setuptools, this will default to " +
+ setuptools_source + "; if you use Distribute, this "
+ "will default to " + distribute_source +"."))
+parser.add_option("--download-base", action="callback", dest="download_base",
+ callback=normalize_to_url, nargs=1, type="string",
+ help=("Specify a URL or directory for downloading "
+ "zc.buildout and either Setuptools or Distribute. "
+ "Defaults to PyPI."))
+parser.add_option("--eggs",
+ help=("Specify a directory for storing eggs. Defaults to "
+ "a temporary directory that is deleted when the "
+ "bootstrap script completes."))
+parser.add_option("-t", "--accept-buildout-test-releases",
+ dest='accept_buildout_test_releases',
+ action="store_true", default=False,
+ help=("Normally, if you do not specify a --version, the "
+ "bootstrap script and buildout gets the newest "
+ "*final* versions of zc.buildout and its recipes and "
+ "extensions for you. If you use this flag, "
+ "bootstrap and buildout will get the newest releases "
+ "even if they are alphas or betas."))
+parser.add_option("-c", None, action="store", dest="config_file",
+ help=("Specify the path to the buildout configuration "
+ "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout's main function
+if options.config_file is not None:
+ args += ['-c', options.config_file]
+
+if options.eggs:
+ eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
+else:
+ eggs_dir = tempfile.mkdtemp()
+
+if options.setup_source is None:
+ if options.use_distribute:
+ options.setup_source = distribute_source
+ else:
+ options.setup_source = setuptools_source
+
+if options.accept_buildout_test_releases:
+ args.append('buildout:accept-buildout-test-releases=true')
+args.append('bootstrap')
+
+try:
+ import pkg_resources
+ import setuptools # A flag. Sometimes pkg_resources is installed alone.
+ if not hasattr(pkg_resources, '_distribute'):
+ raise ImportError
+except ImportError:
+ ez_code = urllib2.urlopen(
+ options.setup_source).read().replace('\r\n', '\n')
+ ez = {}
+ exec ez_code in ez
+ setup_args = dict(to_dir=eggs_dir, download_delay=0)
+ if options.download_base:
+ setup_args['download_base'] = options.download_base
+ if options.use_distribute:
+ setup_args['no_fake'] = True
+ ez['use_setuptools'](**setup_args)
+ if 'pkg_resources' in sys.modules:
+ reload(sys.modules['pkg_resources'])
+ import pkg_resources
+ # This does not (always?) update the default working set. We will
+ # do it.
+ for path in sys.path:
+ if path not in pkg_resources.working_set.entries:
+ pkg_resources.working_set.add_entry(path)
+
+cmd = [quote(sys.executable),
+ '-c',
+ quote('from setuptools.command.easy_install import main; main()'),
+ '-mqNxd',
+ quote(eggs_dir)]
+
+if not has_broken_dash_S:
+ cmd.insert(1, '-S')
+
+find_links = options.download_base
+if not find_links:
+ find_links = os.environ.get('bootstrap-testing-find-links')
+if find_links:
+ cmd.extend(['-f', quote(find_links)])
+
+if options.use_distribute:
+ setup_requirement = 'distribute'
+else:
+ setup_requirement = 'setuptools'
+ws = pkg_resources.working_set
+setup_requirement_path = ws.find(
+ pkg_resources.Requirement.parse(setup_requirement)).location
+env = dict(
+ os.environ,
+ PYTHONPATH=setup_requirement_path)
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+ # Figure out the most recent final version of zc.buildout.
+ import setuptools.package_index
+ _final_parts = '*final-', '*final'
+ def _final_version(parsed_version):
+ for part in parsed_version:
+ if (part[:1] == '*') and (part not in _final_parts):
+ return False
+ return True
+ index = setuptools.package_index.PackageIndex(
+ search_path=[setup_requirement_path])
+ if find_links:
+ index.add_find_links((find_links,))
+ req = pkg_resources.Requirement.parse(requirement)
+ if index.obtain(req) is not None:
+ best = []
+ bestv = None
+ for dist in index[req.project_name]:
+ distv = dist.parsed_version
+ if _final_version(distv):
+ if bestv is None or distv > bestv:
+ best = [dist]
+ bestv = distv
+ elif distv == bestv:
+ best.append(dist)
+ if best:
+ best.sort()
+ version = best[-1].version
+if version:
+ requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+if is_jython:
+ import subprocess
+ exitcode = subprocess.Popen(cmd, env=env).wait()
+else: # Windows prefers this, apparently; otherwise we would prefer subprocess
+ exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
+if exitcode != 0:
+ sys.stdout.flush()
+ sys.stderr.flush()
+ print ("An error occurred when trying to install zc.buildout. "
+ "Look above this message for any errors that "
+ "were output by easy_install.")
+ sys.exit(exitcode)
+
+ws.add_entry(eggs_dir)
+ws.require(requirement)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+if not options.eggs: # clean up temporary egg directory
+ shutil.rmtree(eggs_dir)
Added: grokcore.registries/trunk/buildout.cfg
===================================================================
--- grokcore.registries/trunk/buildout.cfg (rev 0)
+++ grokcore.registries/trunk/buildout.cfg 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+[buildout]
+extends = http://svn.zope.org/repos/main/groktoolkit/trunk/grok.cfg
+develop = .
+parts =
+ test
+ omelette
+extensions =
+ buildout.dumppickedversions
+ mr.developer
+
+[versions]
+grokcore.registries =
+grokcore.component =
+
+[omelette]
+recipe = collective.recipe.omelette
+eggs = ${test:eggs}
+
+[test]
+recipe = zc.recipe.testrunner
+eggs =
+ grokcore.registries
+ grokcore.registries [test]
+defaults = ['--tests-pattern', '^f?tests$', '-v', '--auto-color']
Added: grokcore.registries/trunk/setup.py
===================================================================
--- grokcore.registries/trunk/setup.py (rev 0)
+++ grokcore.registries/trunk/setup.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,57 @@
+from setuptools import setup, find_packages
+import os
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+long_description = (
+ read('README.txt')
+ + '\n' +
+ read('CHANGES.txt')
+ + '\n' +
+ 'Download\n'
+ '********\n'
+ )
+
+tests_require = [
+ 'zope.app.appsetup',
+ 'zope.app.wsgi',
+ 'zope.app.testing',
+ 'grokcore.component',
+ 'grokcore.site',
+ 'zope.testing',
+ ]
+
+setup(
+ name='grokcore.registries',
+ version='0.1',
+ author='Grok Team',
+ author_email='grok-dev at zope.org',
+ url='http://grok.zope.org',
+ download_url='http://cheeseshop.python.org/pypi/grokcore.json/',
+ description='Advanced Registry Behavior for Grok.',
+ long_description=long_description,
+ license='ZPL',
+ classifiers=[
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Programming Language :: Python',
+ 'Framework :: Zope3',
+ ],
+ packages=find_packages('src'),
+ package_dir = {'': 'src'},
+ namespace_packages=['grokcore'],
+ include_package_data = True,
+ zip_safe=False,
+ install_requires=[
+ 'setuptools',
+ 'zope.component',
+ 'zope.configuration',
+ 'zope.interface',
+ 'zope.location',
+ 'zope.schema',
+ ],
+ tests_require=tests_require,
+ extras_require={'test': tests_require},
+)
Added: grokcore.registries/trunk/src/grokcore/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ import pkgutil
+ __path__ = pkgutil.extend_path(__path__, __name__)
Added: grokcore.registries/trunk/src/grokcore/registries/README.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/README.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/README.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,145 @@
+===================
+grokcore.registries
+===================
+
+With the help of this package you are now able to create
+your on BaseComponents Registries. With the help of
+a zcml directive ´registerIn´ you can choose in which
+Registry your grok Components will be registerd.
+
+Setup
+-----
+
+The first thing we have to do is to create an instance of
+a BaseComponents Regsitry. For this task we use the
+create_components_registry.
+
+ >>> from grokcore.registries import create_components_registry
+ >>> from zope.component.interfaces import IComponents
+ >>> import zope.component
+
+ >>> myRegistry = create_components_registry(name="myRegistry")
+
+ >>> myRegistry
+ <BaseComponents myRegistry>
+
+ >>> IComponents.providedBy(myRegistry)
+ True
+
+
+It's possible to create a chain of Registries you have to provide
+your Bases in the third argument of the create_components_registry.
+
+ >>> myOtherRegistry = create_components_registry(
+ ... zope.component.globalSiteManager, 'myRegistry', (myRegistry,))
+ >>> myOtherRegistry.__bases__
+ (<BaseComponents myRegistry>,)
+
+
+Basic Working
+-------------
+
+ >>> custom = create_components_registry(
+ ... zope.component.globalSiteManager, 'custom')
+
+Let's make sure that the parent of the custom registry is the base registry:
+
+ >>> custom.__parent__
+ <BaseGlobalComponents base>
+
+We make the custom Registry a Utility:
+
+ >>> from zope.component.interfaces import IComponents
+ >>> zope.component.provideUtility(custom, IComponents, 'custom')
+
+ >>> custom = zope.component.getUtility(IComponents, name='custom')
+ >>> custom
+ <BaseComponents custom>
+
+
+Now the registerIn function comes into the game. We register all stuff
+from ´registries.global´ to the GlobalSiteManager, and the contents of
+´registries.local´ to our custom Registry.
+ >>> from zope.configuration import xmlconfig
+
+
+ >>> context = xmlconfig.string('''
+ ... <configure i18n_domain="zope">
+ ... <include package="zope.component" file="meta.zcml" />
+ ... <include package="grokcore.registries" file="meta.zcml" />
+ ... <include package="grokcore.site" />
+ ... </configure>
+ ... ''')
+
+ >>> context = xmlconfig.string('''
+ ... <configure xmlns="http://namespaces.zope.org/zope"
+ ... xmlns:grok="http://namespaces.zope.org/grok"
+ ... i18n_domain="zope">
+ ...
+ ... <include package="grokcore.component" file="meta.zcml" />
+ ...
+ ... <grok:grok package="grokcore.registries.tests.registries.global" />
+ ... <registerIn registry="README.custom">
+ ... <grok:grok package="grokcore.registries.tests.registries.local" />
+ ... </registerIn>
+ ...
+ ... </configure>
+ ... ''', context=context)
+
+Now we can verify if we found our Components in the valid registries.
+We start in searching in the GlobalSiteManager:
+
+
+ >>> from grokcore.registries.tests.registries.interfaces import IExample
+ >>> zope.component.getUtility(IExample, name="global")
+ <grokcore.registries.tests.registries.global.MyExample object at ...>
+
+ >>> zope.component.getUtility(IExample, name="local")
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.registries.tests.registries.interfaces.IExample>, 'local')
+
+
+Now we use our ´custom´ one:
+
+ >>> custom.getUtility(IExample, name="global")
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.registries.tests.registries.interfaces.IExample>, 'global')
+
+ >>> custom.getUtility(IExample, name="local")
+ <grokcore.registries.tests.registries.local.MyExample object at ...>
+
+
+Using BaseRegistries (Stacked Registries)
+-----------------------------------------
+
+ >>> from grokcore.site import Application
+ >>> site = Application()
+ >>> from zope.site.site import LocalSiteManager
+ >>> site.setSiteManager(LocalSiteManager(site))
+ >>> sm = site.getSiteManager()
+
+ >>> sm.__bases__
+ (<BaseGlobalComponents base>,)
+
+
+ >>> sm.getUtility(IExample, name="global")
+ <grokcore.registries.tests.registries.global.MyExample object at 0...>
+
+ >>> sm.getUtility(IExample, name="local")
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.registries.tests.registries.interfaces.IExample>, 'local')
+
+If we stack our "custom" registry, in to the GlobalSiteManager we found all registries
+
+ >>> sm.__bases__ += (custom,)
+ >>> sm.__bases__
+ (<BaseGlobalComponents base>, <BaseComponents custom>)
+
+ >>> sm.getUtility(IExample, name="global")
+ <grokcore.registries.tests.registries.global.MyExample object at 0...>
+
+ >>> sm.getUtility(IExample, name="local")
+ <grokcore.registries.tests.registries.local.MyExample object at 0...>
Added: grokcore.registries/trunk/src/grokcore/registries/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from grokcore.registries.components import BaseComponents
+from grokcore.registries.components import create_components_registry
Added: grokcore.registries/trunk/src/grokcore/registries/components.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/components.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/components.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,60 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Base classes for Grok application components.
+
+When an application developer builds a Grok-based application, the
+classes they define each typically inherit from one of the base classes
+provided here.
+
+"""
+
+from grokcore.registries.utils import query_registry, contextualSiteManager
+from zope.component.globalregistry import GlobalAdapterRegistry
+from zope.interface import implements, directlyProvides
+from zope.component.interfaces import IComponents, IComponentLookup
+from zope.component.registry import Components
+from zope.location import Location
+
+
+registries = {}
+
+
+class BaseComponents(Location, Components):
+ implements(IComponentLookup)
+
+ def __init__(self, parent, name, bases=()):
+ self.__name__ = name
+ self.__parent__ = parent
+ self._init_registries()
+ self._init_registrations()
+ self.__bases__ = tuple(bases)
+
+ def _init_registries(self):
+ self.adapters = GlobalAdapterRegistry(self, 'adapters')
+ self.utilities = GlobalAdapterRegistry(self, 'utilities')
+
+ def __reduce__(self):
+ # Global site managers are pickled as global objects
+ return query_registry, (self.__name__, self.__parent__)
+
+
+def create_components_registry(parent=None, name='', bases=()):
+ if parent is None:
+ parent = contextualSiteManager()
+ registry = BaseComponents(parent, name, bases)
+ directlyProvides(registry, IComponents)
+ if name in registries.keys():
+ RuntimeError('Duplicated key for registry %r found.' % name)
+ registries[name] = registry
+ return registry
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore/registries/configure.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/configure.zcml (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/configure.zcml 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:grok="http://namespaces.zope.org/grok">
+
+ <include package="grokcore.site" />
+ <include package="." file="meta.zcml" />
+
+</configure>
Added: grokcore.registries/trunk/src/grokcore/registries/ftesting.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftesting.zcml (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftesting.zcml 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,22 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:grok="http://namespaces.zope.org/grok"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="grokcore.registries"
+ package="grokcore.registries">
+
+ <include package="zope.app.appsetup" file="ftesting.zcml" />
+
+ <include package="grokcore.registries" file="meta.zcml" />
+ <include package="grokcore.registries" />
+
+ <grok:grok package="grokcore.registries.ftests" />
+
+ <grok:grok package="grokcore.registries.tests.registries.global" />
+ <registerIn registry="grokcore.registries.ftests.registries.basic.specialRegistry">
+ <grok:grok package="grokcore.registries.tests.registries.local" />
+ </registerIn>
+
+
+</configure>
+
Added: grokcore.registries/trunk/src/grokcore/registries/ftests/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# package
Added: grokcore.registries/trunk/src/grokcore/registries/ftests/registries/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/registries/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/registries/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# package
Added: grokcore.registries/trunk/src/grokcore/registries/ftests/registries/basic.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/registries/basic.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/registries/basic.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,20 @@
+"""
+ >>> from zope.component import getUtility
+ >>> from grokcore.registries.tests.registries.interfaces import IExample
+
+ >>> getUtility(IExample, name=u'global')
+ <grokcore.registries.tests.registries.global.MyExample object at ...>
+
+ >>> getUtility(IExample, name=u'local')
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.registries.tests.registries.interfaces.IExample>, u'local')
+
+ >>> specialRegistry.getUtility(IExample, name=u'local')
+ <grokcore.registries.tests.registries.local.MyExample object at ...>
+"""
+
+from grokcore.registries import create_components_registry
+
+
+specialRegistry = create_components_registry(name="specialRegistry")
Added: grokcore.registries/trunk/src/grokcore/registries/ftests/registries/creation.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/registries/creation.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/registries/creation.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+ >>> my_registry
+ <BaseComponents my_registry>
+
+ >>> from zope.component.interfaces import IComponents
+ >>> IComponents.providedBy(my_registry)
+ True
+
+ >>> chained_registry
+ <BaseComponents chained_registry>
+
+ >>> chained_registry.__bases__
+ (<BaseComponents my_registry>,)
+"""
+
+import zope.component
+from grokcore.registries import create_components_registry
+
+my_registry = create_components_registry(name="my_registry")
+
+chained_registry = create_components_registry(
+ zope.component.globalSiteManager,
+ 'chained_registry',
+ (my_registry,),
+ )
Added: grokcore.registries/trunk/src/grokcore/registries/ftests/registries/grok_integration.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/registries/grok_integration.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/registries/grok_integration.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,41 @@
+"""
+ >>> root = getRootFolder()
+ >>> create_application(MyApplication, root, 'app')
+ <grokcore.registries.ftests.registries.grok_integration.MyApplication ...>
+
+ >>> from zope.component import getUtility
+ >>> from grokcore.registries.tests.registries.interfaces import IExample
+
+ >>> getUtility(IExample, name=u'global')
+ <grokcore.registries.tests.registries.global.MyExample object at ...>
+
+ >>> getUtility(IExample, name=u'local')
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.registries.tests.registries.interfaces.IExample>, u'local')
+
+ >>> specialRegistry.getUtility(IExample, name=u'local')
+ <grokcore.registries.tests.registries.local.MyExample object at ...>
+
+ >>> app = root['app']
+ >>> from zope.component.hooks import setSite
+ >>> setSite(root['app'])
+
+ >>> getUtility(IExample, name=u'local')
+ <grokcore.registries.tests.registries.local.MyExample object at ...>
+
+ >>> setSite()
+
+"""
+
+from grokcore.site import Application
+from grokcore.site.util import create_application
+from grokcore.registries.ftests.registries.basic import specialRegistry
+
+
+class MyApplication(Application):
+
+ def getSiteManager(self):
+ current = super(MyApplication, self).getSiteManager()
+ current.__bases__ += (specialRegistry,)
+ return current
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore/registries/ftests/registries/utils.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/registries/utils.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/registries/utils.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+"""
+ >>> from grokcore.registries.components import registries
+ >>> from pprint import pprint
+ >>> pprint(registries)
+ {'chained_registry': <BaseComponents chained_registry>,
+ 'my_registry': <BaseComponents my_registry>,
+ 'specialRegistry': <BaseComponents specialRegistry>}
+
+"""
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore/registries/ftests/test_grok_functional.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/ftests/test_grok_functional.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/ftests/test_grok_functional.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,41 @@
+import unittest
+import grokcore.registries
+
+from pkg_resources import resource_listdir
+from zope.testing import doctest
+from zope.app.appsetup.testlayer import ZODBLayer
+
+FunctionalLayer = ZODBLayer(grokcore.registries)
+
+
+def suiteFromPackage(name):
+ files = resource_listdir(__name__, name)
+ suite = unittest.TestSuite()
+ for filename in files:
+ if not filename.endswith('.py'):
+ continue
+ if filename == '__init__.py':
+ continue
+
+ dottedname = 'grokcore.registries.ftests.%s.%s' % (name, filename[:-3])
+ test = doctest.DocTestSuite(
+ dottedname,
+ extraglobs=dict(getRootFolder=FunctionalLayer.getRootFolder),
+ optionflags=(doctest.ELLIPSIS+
+ doctest.NORMALIZE_WHITESPACE+
+ doctest.REPORT_NDIFF)
+ )
+ test.layer = FunctionalLayer
+
+ suite.addTest(test)
+ return suite
+
+def test_suite():
+ suite = unittest.TestSuite()
+ for name in ['registries']:
+ suite.addTest(suiteFromPackage(name))
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
Added: grokcore.registries/trunk/src/grokcore/registries/interfaces.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/interfaces.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/interfaces.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,33 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok interfaces
+"""
+
+from zope.configuration.fields import GlobalObject
+from zope.interface import Interface
+from zope.schema import TextLine
+
+
+class IRegisterInDirective(Interface):
+ """Use the specified registry for registering the contained components.
+ """
+ name = TextLine(
+ title=u"Registration name",
+ description=u"Name under which the registry is or will be registered.",
+ required=False)
+
+ registry = GlobalObject(
+ title=u"Registry",
+ description=u"Python path to the registry to use.",
+ required=False)
Added: grokcore.registries/trunk/src/grokcore/registries/meta.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/meta.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/meta.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,95 @@
+#############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grokkers for Grok-configured components.
+
+This `meta` module contains the actual grokker mechanisms for which the
+Grok web framework is named. A directive in the adjacent `meta.zcml`
+file directs the `martian` library to scan this file, where it discovers
+and registers the grokkers you see below. The grokkers are then active
+and available as `martian` recursively examines the packages and modules
+of a Grok-based web application.
+
+"""
+import warnings
+from zope.component.hooks import setSite, getSite
+from grokcore.registries.components import query_registry
+from zope.configuration.config import GroupingContextDecorator
+from zope.configuration.exceptions import ConfigurationError
+
+
+class ConfigurationWrapperSite(object):
+ """This a minimal fake Site, the only responsibility it has
+ is to store our registry as a SiteManager and return it later.
+ This is needed to fool siteinfo via setSite, zope.component.zcml.handler
+ will grab the registry via zope.component.getSiteManager() then.
+ """
+ def __init__(self, sm):
+ self.sm = sm
+
+ def getSiteManager(self):
+ return self.sm
+
+
+def setActiveRegistry(context, registry):
+ context.original = getSite()
+ fakeSite = ConfigurationWrapperSite(registry)
+ setSite(fakeSite)
+
+
+def resetOriginalRegistry(context):
+ setSite(context.original)
+
+
+class RegisterIn(GroupingContextDecorator):
+
+ # Marker that this directive has been used in the path
+ registryChanged = True
+
+ # Storage for the original site
+ original = None
+
+ def __init__(self, context, name="", registry=None, **kw):
+ if not (bool(name) ^ bool(registry)):
+ raise ConfigurationError(
+ 'You need to provide either the name of the registry or the '
+ 'registry object for the ``registerIn`` directive.')
+
+ if hasattr(context, 'registryChanged') and context.registryChanged:
+ raise ConfigurationError(
+ 'Nested ``registerIn`` directives are not permitted.')
+
+ super(RegisterIn, self).__init__(context, **kw)
+
+ if registry is None:
+ self.registry = query_registry(name)
+ if self.registry is None:
+ raise ConfigurationError(
+ 'No registry component given and no registry registered'
+ ' under the name %r' % name)
+ else:
+ self.registry = registry
+
+ def before(self):
+ self.context.action(
+ discriminator=None,
+ callable=setActiveRegistry,
+ args=(self, self.registry),
+ )
+
+ def after(self):
+ self.context.action(
+ discriminator=None,
+ callable=resetOriginalRegistry,
+ args=(self,),
+ )
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore/registries/meta.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/meta.zcml (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/meta.zcml 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,11 @@
+<configure xmlns="http://namespaces.zope.org/meta">
+
+ <directives namespace="http://namespaces.zope.org/zope">
+ <groupingDirective
+ name="registerIn"
+ schema=".interfaces.IRegisterInDirective"
+ handler=".meta.RegisterIn"
+ />
+ </directives>
+
+</configure>
Added: grokcore.registries/trunk/src/grokcore/registries/tests/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# i am a package
Added: grokcore.registries/trunk/src/grokcore/registries/tests/registries/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/registries/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/registries/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+#package
Added: grokcore.registries/trunk/src/grokcore/registries/tests/registries/base.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/registries/base.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/registries/base.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+import grokcore.component as grok
+from grokcore.registries.tests.registries.interfaces import IExample
+
+
+class MyExample(grok.GlobalUtility):
+ grok.name('override')
+ grok.implements(IExample)
Added: grokcore.registries/trunk/src/grokcore/registries/tests/registries/global.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/registries/global.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/registries/global.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+import grokcore.component as grok
+
+
+from grokcore.registries.tests.registries.interfaces import IExample
+
+
+class MyExample(grok.GlobalUtility):
+ grok.name('global')
+ grok.implements(IExample)
Added: grokcore.registries/trunk/src/grokcore/registries/tests/registries/interfaces.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/registries/interfaces.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/registries/interfaces.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,5 @@
+from zope.interface import Interface
+
+
+class IExample(Interface):
+ pass
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore/registries/tests/registries/local.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/registries/local.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/registries/local.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+import grokcore.component as grok
+
+
+from grokcore.registries.tests.registries.interfaces import IExample
+
+
+class MyExample(grok.GlobalUtility):
+ grok.name('local')
+ grok.implements(IExample)
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore/registries/tests/test_doc.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/tests/test_doc.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/tests/test_doc.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,22 @@
+import doctest
+import unittest
+from zope.app.testing import placelesssetup, setup
+
+def setUp(test):
+ placelesssetup.setUp(test)
+ setup.setUpTestAsModule(test, name='README')
+
+def tearDown(test):
+ placelesssetup.tearDown(test)
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite(
+ '../README.txt',
+ setUp=setUp, tearDown=tearDown,
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+ ),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: grokcore.registries/trunk/src/grokcore/registries/utils.py
===================================================================
--- grokcore.registries/trunk/src/grokcore/registries/utils.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore/registries/utils.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+
+import pkg_resources
+from zope.component import queryUtility, getSiteManager, getGlobalSiteManager
+from zope.component.interfaces import IComponents
+
+
+def contextualSiteManager():
+ return getSiteManager() or getGlobalSiteManager()
+
+
+def query_registry(name, parent_components=None):
+ if parent_components is None:
+ parent_components = contextualSiteManager()
+ return parent_components.getUtility(IComponents, name)
Added: grokcore.registries/trunk/src/grokcore.component/CHANGES.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/CHANGES.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/CHANGES.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,210 @@
+Changes
+=======
+
+2.5 (unreleased)
+----------------
+
+- Introduce provideUtility, providerAdapter, provideSubscriptionAdapter,
+ provideHandler and provideInterface in grokcore.component. These by default
+ delegate the registration of components to the global site manager like
+ was done before, but provide the possibility for custom registries for the
+ grokked components.
+
+- Fix the `global_adapter` to properly use information annotated by
+ ``grok.adapter``, and using the IContext object if it was not
+ specified. (Fix Launchpad issue #960097).
+
+- Add a ``key`` option to ``sort_components`` that behave like ``key``
+ options available on standard Python sort methods.
+
+2.4 (2011-04-27)
+----------------
+
+- Fix the `global_adapter` directive implementation to accept an explicit
+ "empty" name for nameless adapter registrations (as it used to be that
+ providing an empty name in the registration would actually result in
+ registering a named adapter in case the factory has a `grok.name`).
+
+2.3 (2011-02-14)
+----------------
+
+- Implement the generic (Multi)Subscriptions components.
+
+2.2 (2010-11-03)
+----------------
+
+- The default values computation for the context directive and the provides
+ directive is now defined in the directives themselves. This means that where
+ the values for these directives is being retrieved, the "default_context"
+ function does not need to be passed along anymore for general cases.
+
+ Analogous to this, when getting values for the provides directive the
+ "default_provides" function does not need to be passed along in the general
+ case.
+
+2.1 (2010-11-01)
+----------------
+
+* Made package comply to zope.org repository policy.
+
+* Moved directives 'order' from grokcore.viewlet and 'path' from
+ grokcore.view to this very package.
+
+* Tiny dependency adjustment: moved zope.event to test dependencies.
+
+* Port from 1.x branch exclude parameter to the Grok ZCML directive.
+
+* Port from 1.x branch the ignore of testing.py modules.
+
+2.0 (2009-09-16)
+----------------
+
+* Use a newer version of Martian that has better support for
+ inheritance. This is demonstrated in ``tests/inherit``.
+
+* The ``ContextGrokker`` and the ``scan.py`` module have gone away
+ thanks the newer Martian.
+
+* Directive implementations (in their factory method) should *not*
+ bind directives. Directive binding cannot take place at import time,
+ but only at grok time. Binding directives during import time (when
+ directives are executed) can lead to change problems. (we noticed
+ this during our refactoring to use the new Martian).
+
+* Use 1.0b1 versions.cfg in Grok's release info instead of a local
+ copy; a local copy for all grokcore packages is just too hard to
+ maintain.
+
+1.7 (2009-06-01)
+----------------
+
+* Add missing provider, global_adapter, implementsOnly, classProvides() to
+ the module interface so that they are included in __all__
+
+1.6 (2009-04-10)
+----------------
+
+* Add convenience imports for implementsOnly() and classProvides() class
+ declarations form zope.interface.
+
+* Add support for registering global adapters at module level::
+
+ grok.global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
+
+ Only 'factory' is required. If only a single interface is adapted, the
+ second argument may be a single interface instead of a tuple. If the
+ component has declared adapted/provided interfaces, the second and third
+ arguments may be omitted.
+
+* Add support for an @provider decorator to let a function directly provide
+ an interface::
+
+ @grok.provider(IFoo, IBar)
+ def some_function():
+ ...
+
+ This is equivalent to doing alsoProvides(some_function, IFoo, IBar).
+
+* Add support for named adapters with the @adapter decorator::
+
+ @grok.adapter(IAdaptedOne, IAdaptedTwo, name=u"foo")
+ def some_function(one, two):
+ ...
+
+1.5.1 (2008-07-28)
+------------------
+
+* The ``IGrokcoreComponentAPI`` interface was missing declarations for
+ the ``title`` and ``description`` directives.
+
+1.5 (2008-07-22)
+----------------
+
+* Fix https://bugs.launchpad.net/grok/+bug/242353: grokcore.component
+ contains old-style test setup. There is no `register_all_tests`
+ method in grokcore.component.testing anymore. Use z3c.testsetup
+ instead.
+
+* Allow functions that have been marked with @grok.subscribe also be
+ registered with ``zope.component.provideHandler()`` manually. This
+ is useful for unit tests where you may not want to grok a whole
+ module.
+
+* Document grokcore.component's public API in an interface,
+ ``IGrokcoreComponentAPI``. When you now do::
+
+ from grokcore.component import *
+
+ only the items documented in that interface will be imported into
+ your local namespace.
+
+1.4 (2008-06-11)
+----------------
+
+* Ported class grokkers to make use of further improvements in Martian.
+ This requires Martian 0.10.
+
+1.3 (2008-05-14)
+----------------
+
+* Ported class grokkers to make use of the new declarative way of
+ retrieving directive information from a class. This requires
+ Martian 0.9.6.
+
+1.2.1 (2008-05-04)
+------------------
+
+* Upgrade to Martian 0.9.5, which has a slight change in the signature of
+ ``scan_for_classes``.
+
+* Remove an unnecessary import ``methods_from_class`` from
+ ``grokcore.component.scan``.
+
+1.2 (2008-05-04)
+----------------
+
+* Ported directives to Martian's new directive implementation. As a
+ result, nearly all helper functions that were available from
+ ``grokcore.component.util`` have been removed. The functionality is
+ mostly available from the directives themselves now.
+
+* The ``baseclass`` directive has been moved to Martian.
+
+* The ``order`` directive and its helper functions have been moved
+ back to Grok, as it was of no general use, but very specific to
+ viewlets.
+
+1.1 (2008-05-03)
+----------------
+
+* ``determine_module_component`` now looks for classes that implement
+ a certain interface (such as ``IContext``), instead of taking a list
+ of classes. If looking for ``IContext``, it still will find
+ ``Context`` subclasses, as these were also made to implement
+ ``IContext``.
+
+* Move the ``public_methods_from_class`` helper function back to Grok,
+ it isn't used at all in ``grokcore.component``.
+
+1.0.1 (2008-05-02)
+------------------
+
+* The grokkers for adapters and global utilities did not use the
+ correct value for the *provided* interface in the configuration
+ action discriminator. Because of this, uninformative and
+ potentially wrong conflict errors would occur, as well as no
+ conflict where a conflict should have occurred.
+
+* The grokker for the ``global_utility()`` directive did immediate
+ registrations instead of generating configuration actions.
+ Therefore it did not provoke ``ConflictErrors`` for conflicting
+ registrations.
+
+* Improved documentation
+
+1.0 (2008-05-01)
+----------------
+
+* Created ``grokcore.component`` in March 2008 by factoring basic
+ component base classes and their directives and grokkers out of
+ Grok.
Added: grokcore.registries/trunk/src/grokcore.component/COPYRIGHT.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/COPYRIGHT.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/COPYRIGHT.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+Zope Foundation and Contributors
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore.component/CREDITS.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/CREDITS.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/CREDITS.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,6 @@
+CREDITS
+=======
+
+This package was extracted from the Grok web framework.
+
+For credits, see the CREDITS file in the main ``grok`` project itself.
Added: grokcore.registries/trunk/src/grokcore.component/INSTALL.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/INSTALL.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/INSTALL.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,19 @@
+Preparing for grok development
+------------------------------
+
+Install setuptools on your system, or use a setuptools-based
+environment like a "virtualenv" or a "buildout", and then install
+"grokcore.component". Doing it from the command line looks like::
+
+ $ sudo easy_install -U grokcore.component
+
+Then you can try importing it from your Python code.
+
+Running the tests
+-----------------
+
+To run the "grokcore.component" tests, you need to download the source
+code from version control and run the following command which the
+buildout will create::
+
+ $ bin/test
Added: grokcore.registries/trunk/src/grokcore.component/LICENSE.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/LICENSE.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/LICENSE.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,44 @@
+Zope Public License (ZPL) Version 2.1
+
+A copyright notice accompanies this license document that identifies the
+copyright holders.
+
+This license has been certified as open source. It has also been designated as
+GPL compatible by the Free Software Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions in source code must retain the accompanying copyright
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying copyright
+notice, this list of conditions, and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to endorse or promote
+products derived from this software without prior written permission from the
+copyright holders.
+
+4. The right to distribute this software or to use it for any purpose does not
+give you the right to use Servicemarks (sm) or Trademarks (tm) of the
+copyright
+holders. Use of them is covered by separate agreement with the copyright
+holders.
+
+5. If any files are modified, you must cause the modified files to carry
+prominent notices stating that you changed the files and the date of any
+change.
+
+Disclaimer
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Added: grokcore.registries/trunk/src/grokcore.component/README.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/README.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/README.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,225 @@
+This package provides base classes of basic component types for the
+Zope Component Architecture, as well as means for configuring and
+registering them directly in Python (without ZCML).
+
+.. contents::
+
+How to set up ``grokcore.component``
+====================================
+
+In the following we assume you're writing or extending an application
+that does bootstrap configuration using ZCML. There's always a single
+ZCML file that is executed when the application is started, which then
+includes everything else. Let's assume this file is called
+``site.zcml`` (that's what it's called in Zope), so that file is what
+we'll be editing.
+
+In order to register the components that you wrote using the base
+classes and directives available from ``grokcore.component``, we'll
+use the ``<grok:grok />`` ZCML directive. But before we can use it,
+we need to make sure it's available to the ZCML machinery. We do this
+by including the meta configuration from ``grokcore.component``::
+
+ <include package="grokcore.component" file="meta.zcml" />
+
+Put this line somewhere to the top of ``site.zcml``, next to other
+meta configuration includes. Now, further down the line, we can tell
+the machinery in ``grokcore.component`` to register all components in
+your package (let's say it's called ``helloworld``)::
+
+ <grok:grok package="helloworld" />
+
+To sum up, your ``site.zcml`` file should look like something like this::
+
+ <configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:grok="http://namespaces.zope.org/grok">
+
+ <!-- do the meta configuration to make the ZCML directives available -->
+ <include package="zope.foobar" file="meta.zcml" />
+ <include package="zope.frobnaz" file="meta.zcml" />
+ <include package="grokcore.component" file="meta.zcml" />
+
+ <!-- now load the configuration of packages that we depend on -->
+ <include package="zope.barfoo" />
+ <include package="zope.somethingorother" />
+
+ <!-- finally load my components which are based on grokcore.component -->
+ <grok:grok package="helloworld" />
+
+ </configure>
+
+Examples
+========
+
+Adapter
+-------
+
+Here's a simple adapter that may be useful in Zope. It extracts the
+languages that a user prefers from the request::
+
+ import grokcore.component
+ from zope.publisher.interfaces.browser import IBrowserRequest
+ from zope.i18n.interfaces import IUserPreferredLanguages
+
+ class CookieLanguage(grokcore.component.Adapter):
+ """Extract the preferred language from a cookie"""
+ grokcore.component.context(IBrowserRequest)
+ grokcore.component.implements(IUserPreferredLanguages)
+
+ # No need to implement __init__, it's already provided by the base class.
+
+ def getPreferredLanguages(self):
+ # This an adapter for the request, so self.context is the request.
+ request = self.context
+
+ # Extract the preferred language from a cookie:
+ lang = request.cookies.get('language', 'en')
+
+ # According to IUserPreferredLanguages, we must return a list.
+ return [lang]
+
+Multi-adapter
+-------------
+
+Here's a multi-adapter that functions as a content provider as known
+from the ``zope.contentprovider`` library. Content providers are
+components that return snippets of HTML. They're multi-adapters for
+the content object (model), the request and the view that they're
+supposed to be a part of::
+
+ import grokcore.component
+ from zope.publisher.interfaces.browser import IBrowserRequest
+ from zope.publisher.interfaces.browser import IBrowserPage
+ from zope.contentprovider.interfaces import IContentProvider
+
+ class HelloWorldProvider(grokcore.component.MultiAdapter):
+ """Display Hello World!"""
+ grokcore.component.adapts(Interface, IBrowserRequest, IBrowserPage)
+ grokcore.component.implements(IContentProvider)
+
+ def __init__(self, context, request, view):
+ pass
+
+ def update(self):
+ pass
+
+ def render(self):
+ return u'<p>Hello World!</p>'
+
+
+Global utility
+--------------
+
+Here's a simple named utility, again from the Zope world. It's a
+translation domain. In other words, it contains translations of user
+messages and is invoked when the i18n machinery needs to translate
+something::
+
+ import grokcore.component
+ from zope.i18n.interfaces import ITranslationDomain
+
+ class HelloWorldTranslationDomain(grokcore.component.GlobalUtility):
+ grokcore.component.implements(ITranslationDomain)
+ grokcore.component.name('helloworld')
+
+ domain = u'helloworld'
+
+ def translate(self, msgid, mapping=None, context=None,
+ target_language=None, default=None):
+ if target_language is None:
+ preferred = IUserPreferredLanguages(context)
+ target_language = preferred.getPreferredLanguages()[0]
+
+ translations = {'de': u'Hallo Welt',
+ 'nl': u'Hallo Wereld'}
+ return translations.get(target_language, u'Hello World')
+
+Of course, it's silly to implement your own translation domain utility
+if there are already implementations available in ``zope.i18n`` (one
+that reads translations from a GNU gettext message catalog and a
+simple implementation for tests). Let's try to reuse that
+implementation and register an instance::
+
+ import grokcore.component
+ from zope.i18n.interfaces import ITranslationDomain
+ from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
+
+ messages = {('de', u'Hello World'): u'Hallo Welt',
+ ('nl', u'Hello World'): u'Hallo Wereld'}
+ helloworld_domain = SimpleTranslationDomain(u'helloworld', messages)
+
+ grokcore.component.global_utility(helloworld_domain,
+ provides=ITranslationDomain,
+ name='helloworld',
+ direct=True)
+
+Global adapter
+--------------
+
+Sometimes, you may have an object that should be registered as an adapter
+factory. It may have come from some other framework that configured that
+adapter for you, say, or you may have a class that you instantiate many
+times to get different variations on a particular adapter factory. In these
+cases, subclassing grokcore.component.Adapter or MultiAdapter is not
+possible. Instead, you can use the global_adapter() directive. Here is an
+example drawing on the ``z3c.form`` library, which provides an adapter factory
+factory for named widget attributes::
+
+ import zope.interface
+ import zope.schema
+ import grokcore.component
+ import z3c.form.widget import ComputedWidgetAttribute
+
+ class ISchema(Interface):
+ """This schema will be used to power a z3c.form form"""
+
+ field = zope.schema.TextLine(title=u"Sample field")
+
+ ...
+
+ label_override = z3c.form.widget.StaticWidgetAttribute(
+ u"Override label", field=ISchema['field'])
+
+ grokcore.component.global_adapter(label_override, name=u"label")
+
+In the example above, the provided and adapted interfaces are deduced from the
+object returned by the ``StaticWidgetAttribute`` factory. The full syntax
+for global_adapter is::
+
+ global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
+
+The factory must be a callable (the adapter factory). Adapted interfaces are
+given as a tuple. You may use a single interface instead of a one-element
+tuple for single adapters. The provided interface is given as shown. The name
+defaults to u"" (an unnamed adapter).
+
+Handling events
+---------------
+
+Here we see an event handler much like it occurs within Zope itself. It
+subscribes to the modified event for all annotatable objects (in other words,
+objects that can have metadata associated with them). When invoked, it updates
+the Dublin Core 'Modified' property accordingly::
+
+ import datetime
+ import grokcore.component
+ from zope.annotation.interfaces import IAnnotatable
+ from zope.lifecycleevent.interfaces import IObjectModifiedEvent
+ from zope.dublincore.interfaces import IZopeDublinCore
+
+ @grokcore.component.subscribe(IAnnotatable, IObjectModifiedEvent)
+ def updateDublinCoreAfterModification(obj, event):
+ """Updated the Dublin Core 'Modified' property when a modified
+ event is sent for an object."""
+ IZopeDublinCore(obj).modified = datetime.datetime.utcnow()
+
+Subscriptions
+-------------
+
+Subscriptions look similar to Adapter, however, unlike regular adapters,
+subscription adapters are used when we want all of the adapters that adapt an
+object to a particular adapter.
+
+Analogous to MultiAdapter, there is a MultiSubscription component that "adapts"
+multiple objects.
Added: grokcore.registries/trunk/src/grokcore.component/TODO.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/TODO.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/TODO.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,6 @@
+====
+TODO
+====
+
+ - The testing infrastructure needs to be broken out into "grokcore.testing".
+ - The interfaces need to be broken out into "grokcore.interfaces".
Added: grokcore.registries/trunk/src/grokcore.component/bootstrap.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/bootstrap.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/bootstrap.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,258 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
+from optparse import OptionParser
+
+if sys.platform == 'win32':
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ quote = str
+
+# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
+stdout, stderr = subprocess.Popen(
+ [sys.executable, '-Sc',
+ 'try:\n'
+ ' import ConfigParser\n'
+ 'except ImportError:\n'
+ ' print 1\n'
+ 'else:\n'
+ ' print 0\n'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+has_broken_dash_S = bool(int(stdout.strip()))
+
+# In order to be more robust in the face of system Pythons, we want to
+# run without site-packages loaded. This is somewhat tricky, in
+# particular because Python 2.6's distutils imports site, so starting
+# with the -S flag is not sufficient. However, we'll start with that:
+if not has_broken_dash_S and 'site' in sys.modules:
+ # We will restart with python -S.
+ args = sys.argv[:]
+ args[0:0] = [sys.executable, '-S']
+ args = map(quote, args)
+ os.execv(sys.executable, args)
+# Now we are running with -S. We'll get the clean sys.path, import site
+# because distutils will do it later, and then reset the path and clean
+# out any namespace packages from site-packages that might have been
+# loaded by .pth files.
+clean_path = sys.path[:]
+import site
+sys.path[:] = clean_path
+for k, v in sys.modules.items():
+ if (hasattr(v, '__path__') and
+ len(v.__path__)==1 and
+ not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
+ # This is a namespace package. Remove it.
+ sys.modules.pop(k)
+
+is_jython = sys.platform.startswith('java')
+
+setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
+distribute_source = 'http://python-distribute.org/distribute_setup.py'
+
+# parsing arguments
+def normalize_to_url(option, opt_str, value, parser):
+ if value:
+ if '://' not in value: # It doesn't smell like a URL.
+ value = 'file://%s' % (
+ urllib.pathname2url(
+ os.path.abspath(os.path.expanduser(value))),)
+ if opt_str == '--download-base' and not value.endswith('/'):
+ # Download base needs a trailing slash to make the world happy.
+ value += '/'
+ else:
+ value = None
+ name = opt_str[2:].replace('-', '_')
+ setattr(parser.values, name, value)
+
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
+
+Bootstraps a buildout-based project.
+
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", dest="version",
+ help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+ action="store_true", dest="use_distribute", default=False,
+ help="Use Distribute rather than Setuptools.")
+parser.add_option("--setup-source", action="callback", dest="setup_source",
+ callback=normalize_to_url, nargs=1, type="string",
+ help=("Specify a URL or file location for the setup file. "
+ "If you use Setuptools, this will default to " +
+ setuptools_source + "; if you use Distribute, this "
+ "will default to " + distribute_source +"."))
+parser.add_option("--download-base", action="callback", dest="download_base",
+ callback=normalize_to_url, nargs=1, type="string",
+ help=("Specify a URL or directory for downloading "
+ "zc.buildout and either Setuptools or Distribute. "
+ "Defaults to PyPI."))
+parser.add_option("--eggs",
+ help=("Specify a directory for storing eggs. Defaults to "
+ "a temporary directory that is deleted when the "
+ "bootstrap script completes."))
+parser.add_option("-t", "--accept-buildout-test-releases",
+ dest='accept_buildout_test_releases',
+ action="store_true", default=False,
+ help=("Normally, if you do not specify a --version, the "
+ "bootstrap script and buildout gets the newest "
+ "*final* versions of zc.buildout and its recipes and "
+ "extensions for you. If you use this flag, "
+ "bootstrap and buildout will get the newest releases "
+ "even if they are alphas or betas."))
+parser.add_option("-c", None, action="store", dest="config_file",
+ help=("Specify the path to the buildout configuration "
+ "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout's main function
+if options.config_file is not None:
+ args += ['-c', options.config_file]
+
+if options.eggs:
+ eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
+else:
+ eggs_dir = tempfile.mkdtemp()
+
+if options.setup_source is None:
+ if options.use_distribute:
+ options.setup_source = distribute_source
+ else:
+ options.setup_source = setuptools_source
+
+if options.accept_buildout_test_releases:
+ args.append('buildout:accept-buildout-test-releases=true')
+args.append('bootstrap')
+
+try:
+ import pkg_resources
+ import setuptools # A flag. Sometimes pkg_resources is installed alone.
+ if not hasattr(pkg_resources, '_distribute'):
+ raise ImportError
+except ImportError:
+ ez_code = urllib2.urlopen(
+ options.setup_source).read().replace('\r\n', '\n')
+ ez = {}
+ exec ez_code in ez
+ setup_args = dict(to_dir=eggs_dir, download_delay=0)
+ if options.download_base:
+ setup_args['download_base'] = options.download_base
+ if options.use_distribute:
+ setup_args['no_fake'] = True
+ ez['use_setuptools'](**setup_args)
+ reload(sys.modules['pkg_resources'])
+ import pkg_resources
+ # This does not (always?) update the default working set. We will
+ # do it.
+ for path in sys.path:
+ if path not in pkg_resources.working_set.entries:
+ pkg_resources.working_set.add_entry(path)
+
+cmd = [quote(sys.executable),
+ '-c',
+ quote('from setuptools.command.easy_install import main; main()'),
+ '-mqNxd',
+ quote(eggs_dir)]
+
+if not has_broken_dash_S:
+ cmd.insert(1, '-S')
+
+find_links = options.download_base
+if not find_links:
+ find_links = os.environ.get('bootstrap-testing-find-links')
+if find_links:
+ cmd.extend(['-f', quote(find_links)])
+
+if options.use_distribute:
+ setup_requirement = 'distribute'
+else:
+ setup_requirement = 'setuptools'
+ws = pkg_resources.working_set
+setup_requirement_path = ws.find(
+ pkg_resources.Requirement.parse(setup_requirement)).location
+env = dict(
+ os.environ,
+ PYTHONPATH=setup_requirement_path)
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+ # Figure out the most recent final version of zc.buildout.
+ import setuptools.package_index
+ _final_parts = '*final-', '*final'
+ def _final_version(parsed_version):
+ for part in parsed_version:
+ if (part[:1] == '*') and (part not in _final_parts):
+ return False
+ return True
+ index = setuptools.package_index.PackageIndex(
+ search_path=[setup_requirement_path])
+ if find_links:
+ index.add_find_links((find_links,))
+ req = pkg_resources.Requirement.parse(requirement)
+ if index.obtain(req) is not None:
+ best = []
+ bestv = None
+ for dist in index[req.project_name]:
+ distv = dist.parsed_version
+ if _final_version(distv):
+ if bestv is None or distv > bestv:
+ best = [dist]
+ bestv = distv
+ elif distv == bestv:
+ best.append(dist)
+ if best:
+ best.sort()
+ version = best[-1].version
+if version:
+ requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+if is_jython:
+ import subprocess
+ exitcode = subprocess.Popen(cmd, env=env).wait()
+else: # Windows prefers this, apparently; otherwise we would prefer subprocess
+ exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
+if exitcode != 0:
+ sys.stdout.flush()
+ sys.stderr.flush()
+ print ("An error occurred when trying to install zc.buildout. "
+ "Look above this message for any errors that "
+ "were output by easy_install.")
+ sys.exit(exitcode)
+
+ws.add_entry(eggs_dir)
+ws.require(requirement)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+if not options.eggs: # clean up temporary egg directory
+ shutil.rmtree(eggs_dir)
Added: grokcore.registries/trunk/src/grokcore.component/buildout.cfg
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/buildout.cfg (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/buildout.cfg 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,20 @@
+[buildout]
+develop = .
+parts = interpreter test
+extends = http://svn.zope.org/repos/main/groktoolkit/trunk/grok.cfg
+versions = versions
+extensions = buildout.dumppickedversions
+
+[versions]
+grokcore.component =
+
+[interpreter]
+recipe = zc.recipe.egg
+eggs = grokcore.component
+interpreter = python
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = grokcore.component
+ grokcore.component[test]
+defaults = ['--tests-pattern', '^f?tests$', '-v', '--auto-color']
Added: grokcore.registries/trunk/src/grokcore.component/setup.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/setup.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/setup.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,48 @@
+from setuptools import setup, find_packages
+import os
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+long_description = (
+ read('README.txt')
+ + '\n' +
+ read('CHANGES.txt')
+ )
+
+tests_require = [
+ 'zope.event',
+ ]
+
+setup(
+ name='grokcore.component',
+ version='2.5dev',
+ author='Grok Team',
+ author_email='grok-dev at zope.org',
+ url='http://grok.zope.org',
+ download_url='http://pypi.python.org/pypi/grokcore.component',
+ description='Grok-like configuration for basic components '
+ '(adapters, utilities, subscribers)',
+ long_description=long_description,
+ license='ZPL',
+ classifiers=['Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Programming Language :: Python',
+ ],
+
+ packages=find_packages('src'),
+ package_dir={'': 'src'},
+ namespace_packages=['grokcore'],
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=['setuptools',
+ 'martian >= 0.14',
+ 'zope.component',
+ 'zope.configuration',
+ 'zope.interface',
+ # Note: zope.testing is NOT just a test dependency here.
+ 'zope.testing',
+ ],
+ tests_require=tests_require,
+ extras_require={'test': tests_require},
+)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ import pkgutil
+ __path__ = pkgutil.extend_path(__path__, __name__)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,78 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok
+"""
+
+from zope.component import adapts
+adapts.__doc__ = "Declares the types of objects that a multi-adapter adapts."
+
+from zope.interface import implements, implementsOnly, classProvides
+
+from martian import baseclass
+from martian.error import GrokError, GrokImportError
+from martian import ClassGrokker, InstanceGrokker, GlobalGrokker
+
+from grokcore.component.components import (
+ Adapter,
+ Context,
+ GlobalUtility,
+ MultiAdapter,
+ MultiSubscription,
+ Subscription,
+ )
+
+from grokcore.component.directive import (
+ context,
+ description,
+ direct,
+ global_adapter,
+ global_utility,
+ name,
+ order,
+ path,
+ provides,
+ title,
+ )
+
+from grokcore.component.decorators import (
+ adapter,
+ implementer,
+ provider,
+ subscribe,
+ )
+
+from grokcore.component.subscription import (
+ queryMultiSubscriptions,
+ queryOrderedMultiSubscriptions,
+ queryOrderedSubscriptions,
+ querySubscriptions,
+ )
+
+from grokcore.component.util import (
+ getSiteManager,
+ provideAdapter,
+ provideHandler,
+ provideInterface,
+ provideSubscriptionAdapter,
+ provideUtility,
+ sort_components,
+ )
+
+# Import this module so that it's available as soon as you import the
+# 'grokcore.component' package. Useful for tests and interpreter examples.
+import grokcore.component.testing
+
+# Only export public API
+from grokcore.component.interfaces import IGrokcoreComponentAPI
+__all__ = list(IGrokcoreComponentAPI)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/components.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/components.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/components.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,112 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok components"""
+
+from zope.interface import implements
+
+from grokcore.component.interfaces import IContext
+
+
+class Adapter(object):
+ """Base class for an adapter that adapts a single object (commonly referred
+ to as the *context*).
+
+ Use the ``context`` directive to specify which object to adapt and the
+ ``implements`` directive to specify which interface the adapter will
+ provide. If it's a named adapter, you may use the ``name`` directive to
+ specify the name.
+
+ .. attribute:: context
+
+ The adapted object.
+
+ """
+
+ def __init__(self, context):
+ self.context = context
+
+
+class MultiAdapter(object):
+ """Base class for an adapter that adapts *n* objects (where *n>=1*).
+
+ Use the ``adapts`` directive to specify which kinds of objects are adapted
+ and the ``implements`` directive to specify which interface the adapter
+ will provide. If it's a named multi-adapter, you may use the ``name``
+ directive to specify the name.
+
+ Note that contrary to the Adapter, the MultiAdapter base class does not
+ provide an `__init__` method. An `__init__` needs to accept the same number
+ of arguments as are used in the `adapts` directive.
+
+ """
+ pass
+
+
+class GlobalUtility(object):
+ """Base class to define a globally registered utility.
+
+ Base class for a globally registered utility. Unless you use the ``direct``
+ directive to indicate that the class itself should be registered as a
+ utility, the class will automatically be instantiated, therefore the
+ constructor may not take any arguments. Use the ``implements`` directive to
+ specify which interface the utility provides, or if that is not
+ unambiguous, also use the ``provides`` directive to specify which of the
+ implemented interfaces should be used when registering the utility. If it's
+ a named utility, you may use the ``name`` directive to specify the name.
+
+ """
+ pass
+
+
+class Subscription(object):
+ """Base class for a subscription adapter.
+
+ Subscriptions are similar to adapters, except that it is possible to
+ register multiple unnamed subscriptions for identical ``context`` and
+ ``provides``.
+
+ Use the ``context`` directive to explicitly set the interface to adapt
+ from. When omitted the current context is assumed. Use the ``implements``
+ directive to specify which interface the subscription provides, or if that
+ is not unambiguous, also use the ``provides`` directive to specify which of
+ the implemented interfaces should be used when registering the subscription.
+
+ """
+
+ def __init__(self, context):
+ self.context = context
+
+
+class MultiSubscription(object):
+ """Base class for a subscription multi-adapter.
+
+ MultiSubscriptions are similar to multi adapters, except that it is
+ possible to register multiple unnamed subscriptions for identical
+ ``adapts`` and ``provides``.
+
+ Use the ``adapts`` directive to explicitly set the multiple interfaces to
+ adapt from. Use the ``implements`` directive to specify which interface the
+ subscription provides, or if that is not unambiguous, also use the
+ ``provides`` directive to specify which of the implemented interfaces
+ should be used when registering the multi subscription.
+
+ """
+
+
+class Context(object):
+ """Subclasses of this will automatically be found as potential contexts for
+ adapters and other types of context-dependent components.
+
+ """
+ implements(IContext)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/decorators.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/decorators.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/decorators.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,131 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok
+"""
+import sys
+import types
+import zope.component
+import zope.interface
+from martian.util import frame_is_module
+from martian.error import GrokImportError
+
+from zope.interface.declarations import DescriptorAwareMetaClasses
+
+class subscribe:
+ """Declares that a function is to be registered as an event handler for the
+ specified objects.
+
+ Normally, an event handler is simply registered as a subscriber for the
+ event interface. In case of object events, the event handler is registered
+ as a subscriber for the object type and the event interface.
+
+ """
+ def __init__(self, *args):
+ self.subscribed = args
+
+ def __call__(self, function):
+ frame = sys._getframe(1)
+ if not frame_is_module(frame):
+ raise GrokImportError("@grok.subscribe can only be used on module "
+ "level.")
+
+ if not self.subscribed:
+ raise GrokImportError("@grok.subscribe requires at least one "
+ "argument.")
+
+ # Add the function and subscribed interfaces to the
+ # grok.subscribers module annotation.
+ subscribers = frame.f_locals.get('__grok_subscribers__', None)
+ if subscribers is None:
+ frame.f_locals['__grok_subscribers__'] = subscribers = []
+ subscribers.append((function, self.subscribed))
+
+ # Also store the subscribed interfaces on the
+ # attribute__component_adapts__ for provideHandler to register
+ # the subscriber (in case you don't grok your package and
+ # register it manually)
+ return zope.component.adapter(*self.subscribed)(function)
+
+class adapter(zope.component.adapter):
+ """Registers the function as an adapter for the specific interface.
+
+ The ``name`` argument must be a keyword argument and is optional. If given,
+ a named adapter is registered.
+ """
+
+ # Override the z.c.adapter decorator to force sanity checking and
+ # have better error reporting and add the ability to capture the name
+
+ def __init__(self, *interfaces, **kw):
+ if not interfaces:
+ raise GrokImportError(
+ "@grok.adapter requires at least one argument.")
+ if type(interfaces[0]) is types.FunctionType:
+ raise GrokImportError(
+ "@grok.adapter requires at least one argument.")
+
+ self.name = u""
+
+ if kw:
+ if 'name' in kw:
+ self.name = kw.pop('name')
+ if kw:
+ raise GrokImportError(
+ "@grok.adapter got unexpected keyword arguments: %s" % ','.join(kw.keys()))
+
+ zope.component.adapter.__init__(self, *interfaces)
+
+ def __call__(self, ob):
+ ob = zope.component.adapter.__call__(self, ob)
+ if self.name:
+ ob.__component_name__ = self.name
+ return ob
+
+class implementer(zope.interface.implementer):
+ """Declares that the function implements a certain interface (or a number
+ of interfaces).
+
+ This is useful when a function serves as an object factory, e.g. as an
+ adapter.
+
+ """
+
+ def __call__(self, ob):
+ # XXX we do not have function grokkers (yet) so we put the annotation
+ # on the module.
+ frame = sys._getframe(1)
+ adapters = frame.f_locals.get('__grok_adapters__', None)
+ if adapters is None:
+ frame.f_locals['__grok_adapters__'] = adapters = []
+ adapters.append(ob)
+
+ return zope.interface.implementer.__call__(self, ob)
+
+class provider:
+ """Declares that the function object provides a certain interface (or a
+ number of interfaces).
+
+ This is akin to calling directlyProvides() on the function object.
+
+ """
+ def __init__(self, *interfaces):
+ self.interfaces = interfaces
+
+ def __call__(self, ob):
+ if isinstance(ob, DescriptorAwareMetaClasses):
+ raise TypeError("Can't use implementer with classes. Use one of "
+ "the class-declaration functions instead."
+ )
+ zope.interface.alsoProvides(ob, *self.interfaces)
+ return ob
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/directive.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/directive.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/directive.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,172 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok directives.
+"""
+import martian
+import martian.util
+from martian.error import GrokError, GrokImportError
+from martian.util import scan_for_classes
+from zope import interface
+from zope.interface.interfaces import IInterface
+from grokcore.component.interfaces import IContext
+
+class global_utility(martian.MultipleTimesDirective):
+ """Registers an instance of ``class`` (or ``class`` itself, depending on
+ the value of the ``direct`` parameter) as a global utility.
+
+ This allows you to register global utilities that don't inherit from the
+ ``GlobalUtility`` base class.
+
+ :param class: The class to register as a global utility.
+ :param provides: Optionally, the interface the utility will provide.
+ :param name: Optionally, a name for a named utility registration.
+ :type name: string or unicode
+ :param direct: Optionally, a flag indicating the class directly provides
+ the interfaces, and it needs not to be instantiated.
+ :type direct: boolean
+ """
+ scope = martian.MODULE
+
+ def factory(self, factory, provides=None, name=u'', direct=False):
+ if provides is not None and not IInterface.providedBy(provides):
+ raise GrokImportError(
+ "You can only pass an interface to the "
+ "provides argument of %s." % self.name)
+ return (factory, provides, name, direct)
+
+class global_adapter(martian.MultipleTimesDirective):
+ """Registers the ``factory`` callable as a global adapter.
+
+ This allows you to register global adapters that
+ don't inherit from the ``Adapter`` or ``MultiAdapter`` base classes.
+
+ :param factory: The class that implements the adaptation.
+ :param adapts: Optionally, a single interface or a tuple of multiple
+ interfaces to adapts from. If omitted, this information is
+ deduced from the annotation on the factory. If no adapted
+ interface can be determined the current context will be
+ assumed.
+ :param provides: Optionally, the interface the adapter will provide. If
+ omitted, this information is deduced from the annotations
+ on the factory.
+ :param name: Optionally, a name for a named adapter registration.
+ :type name: string or unicode
+
+ """
+ scope = martian.MODULE
+
+ def factory(self, factory, adapts=None, provides=None, name=None):
+ if provides is not None and not IInterface.providedBy(provides):
+ raise GrokImportError(
+ "You can only pass an interface to the "
+ "provides argument of %s." % self.name)
+ if adapts is None:
+ adapts = getattr(factory, '__component_adapts__', None)
+ elif not isinstance(adapts, (list, tuple,)):
+ adapts = (adapts,)
+ elif isinstance(adapts, list):
+ adapts = tuple(adapts)
+
+ return (factory, adapts, provides, name)
+
+class name(martian.Directive):
+ """Declares the name of a named utility, named adapter, etc.
+
+ """
+ scope = martian.CLASS
+ store = martian.ONCE
+ validate = martian.validateText
+ default = u''
+
+class context(martian.Directive):
+ """Declares the type of object that the adapter (or a similar context-
+ dependent component) adapts.
+
+ :param context: Interface (in this case all objects providing this
+ interface will be eligible contexts for the adaptation) or
+ a class (then only instances of that particular class are
+ eligible).
+ """
+
+ scope = martian.CLASS_OR_MODULE
+ store = martian.ONCE
+ validate = martian.validateInterfaceOrClass
+
+ @classmethod
+ def get_default(cls, component, module=None, **data):
+ components = list(scan_for_classes(module, IContext))
+ if len(components) == 0:
+ raise GrokError(
+ "No module-level context for %r, please use the 'context' "
+ "directive." % (component), component)
+ elif len(components) == 1:
+ component = components[0]
+ else:
+ raise GrokError(
+ "Multiple possible contexts for %r, please use the 'context' "
+ "directive."
+ % (component), component)
+ return component
+
+class title(martian.Directive):
+ """Declares the human-readable title of a component (such as a permission,
+ role, etc.)
+
+ """
+ scope = martian.CLASS
+ store = martian.ONCE
+ validate = martian.validateText
+
+class description(title):
+ pass
+
+class direct(martian.MarkerDirective):
+ """Declares that a ``GlobalUtility`` class should be registered as a
+ utility itself, rather than an instance of it.
+
+ """
+ scope = martian.CLASS
+
+class order(martian.Directive):
+ scope = martian.CLASS
+ store = martian.ONCE
+ default = 0, 0
+
+ _order = 0
+
+ def factory(self, value=0):
+ order._order += 1
+ return value, order._order
+
+class path(martian.Directive):
+ scope = martian.CLASS
+ store = martian.ONCE
+ validate = martian.validateText
+
+class provides(martian.Directive):
+ """Declares the interface that a adapter or utility provides for the
+ registration, as opposed to potentially multiple interfaces that the class
+ implements.
+
+ :param interface: The interface the registered component will provide.
+
+ """
+ scope = martian.CLASS
+ store = martian.ONCE
+ validate = martian.validateInterface
+
+ @classmethod
+ def get_default(cls, component, module, **data):
+ martian.util.check_implements_one(component)
+ return list(interface.implementedBy(component))[0]
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/interfaces.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/interfaces.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/interfaces.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,239 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Public interfaces.
+"""
+from zope.interface import Interface, Attribute
+
+class IContext(Interface):
+ """Marker interface for auto-association of context.
+
+ The ``grok.context()`` directive is used to associate adapters with the
+ class or interface they adapt. If there is only a single possible context
+ object to adapt to in a module, you can leave out this directive and
+ let the adapter associate automatically.
+
+ If you want to make an object to be a candidate for this automatic
+ association, you can subclass from ``grokcore.component.Context``.
+ This implements this ``IContext`` directive.
+
+ In some cases, you don't want to mix in a base class. You can instead
+ mark up your class with ``zope.interface.implements(IContext)`` to make
+ it a candidate for auto-association.
+ """
+
+
+class IBaseClasses(Interface):
+ Adapter = Attribute("Base class for adapters.")
+
+ ClassGrokker = Attribute("Base class to define a class grokker.")
+
+ Context = Attribute("Base class for automatically associated contexts.")
+
+ GlobalGrokker = Attribute("Base class to define a module grokker.")
+
+ GlobalUtility = Attribute("Base class for global utilities.")
+
+ InstanceGrokker = Attribute("Base class to define an instance grokker.")
+
+ MultiAdapter = Attribute("Base class for multi-adapters.")
+
+ MultiSubscription = Attribute(
+ "Base class for subscription mult-adapters.")
+
+ Subscription = Attribute("Base class for subscription adapters.")
+
+
+class IDirectives(Interface):
+
+ def baseclass():
+ """Mark this class as a base class.
+
+ This means it won't be grokked, though if it's a possible context,
+ it can still serve as a context.
+ """
+
+ def implements(*interfaces):
+ """Declare that a class implements the given interfaces."""
+
+ def implementsOnly(*interfaces):
+ """Declare that a class implements only the given interfaces.
+
+ Interfaces implemented by base classes are explicitly not inherited.
+ """
+
+ def classProvides(*interfaces):
+ """Declare that a class (as opposed to instances of the class)
+ directly provides the given interfaces.
+ """
+
+ def adapts(*classes_or_interfaces):
+ """Declare that a class adapts objects of the given classes or
+ interfaces."""
+
+ def context(class_or_interface):
+ """Declare the context for views, adapters, etc.
+
+ This directive can be used on module and class level. When
+ used on module level, it will set the context for all views,
+ adapters, etc. in that module. When used on class level, it
+ will set the context for that particular class."""
+
+ def name(name):
+ """Declare the name of a view or adapter/multi-adapter.
+
+ This directive can only be used on class level."""
+
+ def title(title):
+ """Set a human-readable title for a component (e.g. a
+ permission, menu item, etc.).
+
+ This directive expects pure ASCII strings or Unicode and can
+ only be used on a class level."""
+
+ def description(description):
+ """Set a human-readable description for a component (e.g. a
+ permission, menu item, etc.).
+
+ This directive expects pure ASCII strings or Unicode and can
+ only be used on a class level."""
+
+ def provides(interface):
+ """Explicitly specify with which interface a component will be
+ looked up."""
+
+ def global_utility(factory, provides=None, name=u''):
+ """Register a global utility.
+
+ factory - the factory that creates the global utility
+ provides - the interface the utility should be looked up with
+ name - the name of the utility
+ """
+
+ def global_adapter(factory, adapts=None, provides=None, name=u''):
+ """Register a global adapter.
+
+ factory - the adapter factory, a callable
+ adapts - an interface or list of interfaces adapted
+ provides - the interface provided by the adapter
+ name - the name of the adapter
+ """
+
+ def direct():
+ """Specify whether the class should be used for the component
+ or whether it should be used to instantiate the component.
+
+ This directive can be used on GlobalUtility-based classes to
+ indicate whether the class itself should be registered as a
+ utility, or an instance of it.
+ """
+
+ def order(value=None):
+ """Control the ordering of components.
+
+ If the value is specified, the order will be determined by sorting on
+ it.
+ If no value is specified, the order will be determined by definition
+ order within the module.
+ If the directive is absent, the order will be determined by class name.
+ (unfortunately our preferred default behavior on absence which would
+ be like grok.order() without argument is hard to implement in Python)
+
+ Inter-module order is by dotted name of the module the
+ components are in; unless an explicit argument is specified to
+ ``grok.order()``, components are grouped by module.
+
+ The function grok.util.sort_components can be used to sort
+ components according to these rules.
+ """
+
+
+class IDecorators(Interface):
+
+ def subscribe(*classes_or_interfaces):
+ """Declare that a function subscribes to an event or a
+ combination of objects and events."""
+
+ def adapter(*classes_or_interfaces):
+ """Describes that a function adapts an object or a combination
+ of objects.
+ """
+
+ def implementer(*interfaces):
+ """Describes that a function that's used as an adapter
+ implements an interface or a number of interfaces.
+ """
+
+ def provider(*interfaces):
+ """Describes that a function directly provides an interface or a
+ number of interfaces.
+ """
+
+
+class IGrokErrors(Interface):
+
+ def GrokError(message, component):
+ """Error indicating that a problem occurrend during the
+ grokking of a module (at "grok time")."""
+
+ def GrokImportError(*args):
+ """Error indicating a problem at import time."""
+
+
+class IMartianAPI(Interface):
+ """Part of Martian's API exposed by grokcore.component.
+ """
+
+ ClassGrokker = Attribute("Grokker for classes.")
+
+ GlobalGrokker = Attribute("Grokker that's invoked for a module.")
+
+ InstanceGrokker = Attribute("Grokker for instances.")
+
+
+class IGrokcoreComponentAPI(
+ IBaseClasses,
+ IDecorators,
+ IDirectives,
+ IGrokErrors,
+ IMartianAPI,
+ ):
+ """grokcore.component's public API.
+ """
+
+ getSiteManager = Attribute('Get the site manager for the nearest site.')
+
+ provideAdapter = Attribute('Registers an adapters')
+
+ provideHandler = Attribute('Registers an handler')
+
+ provideInterface = Attribute('Regsiters an interfaces as a utility')
+
+ provideSubscriptionAdapter = Attribute(
+ 'Registers an subscriptions adapter')
+
+ provideUtility = Attribute('Registers an utility')
+
+ querySubscriptions = Attribute("Function to query subscriptions.")
+
+ queryOrderedSubscriptions = Attribute(
+ "Function to query subscription in order.")
+
+ queryMultiSubscriptions = Attribute("Function to query subscriptions.")
+
+ queryOrderedMultiSubscriptions = Attribute(
+ "Function to query subscriptions in order.")
+
+ sort_components = Attribute(
+ 'Sort a list of components using the information provided by '
+ '`grok.order`.')
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,243 @@
+#############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grokkers for the various components."""
+
+import operator
+
+import martian
+import martian.util
+import grokcore.component
+import zope.component.interface
+from zope import component, interface
+from martian.error import GrokError
+from zope.interface import implementedBy
+
+def _provides(component, module=None, **data):
+ martian.util.check_implements_one(component)
+ return list(interface.implementedBy(component))[0]
+
+def default_global_utility_provides(component, module, direct, **data):
+ if direct:
+ martian.util.check_provides_one(component)
+ return list(interface.providedBy(component))[0]
+ return _provides(component)
+
+
+class AdapterGrokker(martian.ClassGrokker):
+ martian.component(grokcore.component.Adapter)
+ martian.directive(grokcore.component.context)
+ martian.directive(grokcore.component.provides)
+ martian.directive(grokcore.component.name)
+
+ def execute(self, factory, config, context, provides, name, **kw):
+ config.action(
+ discriminator=('adapter', context, provides, name),
+ callable=grokcore.component.provideAdapter,
+ args=(factory, (context,), provides, name),
+ )
+ return True
+
+
+class MultiAdapterGrokker(martian.ClassGrokker):
+ martian.component(grokcore.component.MultiAdapter)
+ martian.directive(grokcore.component.provides)
+ martian.directive(grokcore.component.name)
+
+ def execute(self, factory, config, provides, name, **kw):
+ for_ = component.adaptedBy(factory)
+ if for_ is None:
+ raise GrokError("%r must specify which contexts it adapts "
+ "(use the 'adapts' directive to specify)."
+ % factory, factory)
+
+ config.action(
+ discriminator=('adapter', for_, provides, name),
+ callable=grokcore.component.provideAdapter,
+ args=(factory, None, provides, name),
+ )
+ return True
+
+
+class SubscriptionGrokker(martian.ClassGrokker):
+ martian.component(grokcore.component.Subscription)
+ martian.directive(grokcore.component.context)
+ martian.directive(grokcore.component.provides)
+ martian.directive(grokcore.component.name)
+
+ def execute(self, factory, config, context, provides, name, **kw):
+ config.action(
+ discriminator=None,
+ callable=grokcore.component.provideSubscriptionAdapter,
+ args=(factory, (context,), provides),
+ )
+ return True
+
+
+class MultiSubscriptionGrokker(martian.ClassGrokker):
+ martian.component(grokcore.component.MultiSubscription)
+ martian.directive(grokcore.component.provides)
+ martian.directive(grokcore.component.name)
+
+ def execute(self, factory, config, provides, name, **kw):
+ adapts = component.adaptedBy(factory)
+ if adapts is None:
+ raise GrokError("%r must specify which contexts it adapts "
+ "(use the 'adapts' directive to specify)."
+ % factory, factory)
+
+ config.action(
+ discriminator=None,
+ callable=grokcore.component.provideSubscriptionAdapter,
+ args=(factory, adapts, provides),
+ )
+ return True
+
+
+class GlobalUtilityGrokker(martian.ClassGrokker):
+ martian.component(grokcore.component.GlobalUtility)
+
+ # This needs to happen before the FilesystemPageTemplateGrokker grokker
+ # happens, since it relies on the ITemplateFileFactories being grokked.
+ martian.priority(1100)
+
+ martian.directive(grokcore.component.direct)
+ martian.directive(grokcore.component.provides,
+ get_default=default_global_utility_provides)
+ martian.directive(grokcore.component.name)
+
+ def execute(self, factory, config, direct, provides, name, **kw):
+ if not direct:
+ factory = factory()
+
+ config.action(
+ discriminator=('utility', provides, name),
+ callable=grokcore.component.provideUtility,
+ args=(factory, provides, name),
+ )
+ return True
+
+
+class ImplementerDecoratorGrokker(martian.GlobalGrokker):
+
+ def grok(self, name, module, module_info, config, **kw):
+ adapters = module_info.getAnnotation('grok.adapters', [])
+ subscribers = set(map(operator.itemgetter(0),
+ module_info.getAnnotation('grok.subscribers', [])))
+
+ for function in adapters:
+ if function in subscribers:
+ # We don't register functions that are decorated with
+ # grok.implementer() *and* the grok.subscribe()
+ # decorator. These are registered as so called
+ # subcribers and not as regular adapters.
+ continue
+ interfaces = getattr(function, '__component_adapts__', None)
+ if interfaces is None:
+ context = grokcore.component.context.bind().get(module)
+ interfaces = (context, )
+ name = getattr(function, '__component_name__', u"")
+ config.action(
+ discriminator=('adapter', interfaces, function.__implemented__, name),
+ callable=grokcore.component.provideAdapter,
+ args=(function, interfaces, function.__implemented__, name),
+ )
+ return True
+
+class GlobalUtilityDirectiveGrokker(martian.GlobalGrokker):
+
+ def grok(self, name, module, module_info, config, **kw):
+ infos = grokcore.component.global_utility.bind().get(module)
+
+ for factory, provides, name, direct in infos:
+ if direct is None:
+ direct = grokcore.component.direct.bind().get(factory)
+ if provides is None:
+ bound = grokcore.component.provides.bind(default=None)
+ provides = bound.get(factory)
+ if not name:
+ name = grokcore.component.name.bind().get(factory)
+
+ if direct:
+ obj = factory
+ if provides is None:
+ martian.util.check_provides_one(obj)
+ provides = list(interface.providedBy(obj))[0]
+ else:
+ obj = factory()
+ if provides is None:
+ provides = _provides(factory)
+
+ config.action(
+ discriminator=('utility', provides, name),
+ callable=grokcore.component.provideUtility,
+ args=(obj, provides, name),
+ )
+
+ return True
+
+
+class GlobalAdapterDirectiveGrokker(martian.GlobalGrokker):
+
+ def grok(self, name, module, module_info, config, **kw):
+ infos = grokcore.component.global_adapter.bind().get(module)
+ for factory, adapts, provides, name in infos:
+ if provides is None:
+ bound = grokcore.component.provides.bind(default=None)
+ provides = bound.get(factory)
+ if adapts is None:
+ adapts = (grokcore.component.context.bind().get(module),)
+ if name is None:
+ name = grokcore.component.name.bind().get(factory)
+
+ config.action(
+ discriminator=('adapter', adapts, provides, name),
+ callable=grokcore.component.provideAdapter,
+ args=(factory, adapts, provides, name),
+ )
+
+ return True
+
+
+class SubscriberDirectiveGrokker(martian.GlobalGrokker):
+
+ def grok(self, name, module, module_info, config, **kw):
+ subscribers = module_info.getAnnotation('grok.subscribers', [])
+
+ for factory, subscribed in subscribers:
+ provides = None
+ implemented = list(implementedBy(factory))
+ if len(implemented) == 1:
+ provides = implemented[0]
+ # provideHandler is essentially the same as
+ # provideSubscriptionAdapter, where provided=None. However,
+ # handlers and subscription adapters are tracked in
+ # separately so we cannot exchange one registration call
+ # for the the other.
+ if provides is None:
+ config.action(
+ discriminator=None,
+ callable=grokcore.component.provideHandler,
+ args=(factory, subscribed))
+ else:
+ config.action(
+ discriminator=None,
+ callable=grokcore.component.provideSubscriptionAdapter,
+ args=(factory, subscribed, provides))
+
+ for iface in subscribed:
+ config.action(
+ discriminator=None,
+ callable=grokcore.component.provideInterface,
+ args=('', iface))
+ return True
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.zcml (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/meta.zcml 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,17 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:meta="http://namespaces.zope.org/meta"
+ xmlns:grok="http://namespaces.zope.org/grok">
+
+ <meta:directives namespace="http://namespaces.zope.org/grok">
+ <meta:directive
+ name="grok"
+ schema=".zcml.IGrokDirective"
+ handler=".zcml.grokDirective"
+ />
+ </meta:directives>
+
+ <!-- Load the grokkers -->
+ <grok:grok package=".meta" />
+
+</configure>
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/subscription.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/subscription.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/subscription.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,41 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok subscriptions functions.
+"""
+from zope import component
+from grokcore.component import util
+
+def queryOrderedMultiSubscriptions(components, interface):
+ return util.sort_components(component.subscribers(components, interface))
+
+def queryOrderedSubscriptions(component, interface):
+ return queryOrderedMultiSubscriptions((component, ), interface)
+
+def queryMultiSubscriptions(components, interface):
+ """Query for subscriptions on the `components` providing `interface`.
+
+ :parameter components: tuple of components to lookup the subscription for.
+ :parameter interface: interface that the subscriptions should provide.
+ :return: a list of subscriptions.
+ """
+ return component.subscribers(components, interface)
+
+def querySubscriptions(component, interface):
+ """Query for subscriptions on `component` providing `interface`.
+
+ :parameter component: a component to lookup the subscriptions for.
+ :parameter interface: interface that the subscriptions should provide.
+ :return: a list of subscription.
+ """
+ return queryMultiSubscriptions((component,), interface)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_display_form.pt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,36 @@
+<html>
+<head>
+</head>
+
+<body>
+ <table class="listing">
+ <thead>
+ <tr>
+ <th class="label-column"> </th>
+ <th> </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tal:block repeat="widget view/widgets">
+ <tr tal:define="odd repeat/widget/odd"
+ tal:attributes="class python: odd and 'odd' or 'even'">
+ <td class="fieldname">
+ <tal:block content="widget/label"/>
+ </td>
+ <td>
+ <input tal:replace="structure widget" />
+ </td>
+ </tr>
+ </tal:block>
+ </tbody>
+ <tfoot>
+ <tr class="controls">
+ <td colspan="2" class="align-right">
+ <input tal:repeat="action view/actions"
+ tal:replace="structure action/render" />
+ </td>
+ </tr>
+ </tfoot>
+ </table>
+</body>
+</html>
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/templates/default_edit_form.pt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,69 @@
+<html>
+<head>
+</head>
+
+<body>
+<form action="." tal:attributes="action request/URL" method="post"
+ class="edit-form" enctype="multipart/form-data">
+
+ <h1 i18n:translate=""
+ tal:condition="view/label"
+ tal:content="view/label">Label</h1>
+
+ <div class="form-status"
+ tal:define="status view/status"
+ tal:condition="status">
+
+ <div i18n:translate="" tal:content="view/status">
+ Form status summary
+ </div>
+
+ <ul class="errors" tal:condition="view/errors">
+ <li tal:repeat="error view/error_views">
+ <span tal:replace="structure error">Error Type</span>
+ </li>
+ </ul>
+ </div>
+
+ <table class="form-fields">
+ <tbody>
+ <tal:block repeat="widget view/widgets">
+ <tr>
+ <td class="label" tal:define="hint widget/hint">
+ <label tal:condition="python:hint"
+ tal:attributes="for widget/name">
+ <span class="required" tal:condition="widget/required"
+ >*</span><span i18n:translate=""
+ tal:content="widget/label">label</span>
+ </label>
+ <label tal:condition="python:not hint"
+ tal:attributes="for widget/name">
+ <span class="required" tal:condition="widget/required"
+ >*</span><span i18n:translate=""
+ tal:content="widget/label">label</span>
+ </label>
+ </td>
+ <td class="field">
+ <div class="widget" tal:content="structure widget">
+ <input type="text" />
+ </div>
+ <div class="error" tal:condition="widget/error">
+ <span tal:replace="structure widget/error">error</span>
+ </div>
+ </td>
+ </tr>
+ </tal:block>
+ </tbody>
+ </table>
+
+ <div id="actionsView">
+ <span class="actionButtons" tal:condition="view/availableActions">
+ <input tal:repeat="action view/actions"
+ tal:replace="structure action/render"
+ />
+ </span>
+ </div>
+</form>
+
+</body>
+</html>
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/testing.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/testing.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/testing.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,45 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok test helpers
+"""
+import grokcore.component
+from zope.configuration.config import ConfigurationMachine
+from martian import scan
+from grokcore.component import zcml
+
+def grok(module_name):
+ config = ConfigurationMachine()
+ zcml.do_grok('grokcore.component.meta', config)
+ zcml.do_grok(module_name, config)
+ config.execute_actions()
+
+def grok_component(name, component,
+ context=None, module_info=None, templates=None):
+ if module_info is None:
+ obj_module = getattr(component, '__grok_module__', None)
+ if obj_module is None:
+ obj_module = getattr(component, '__module__', None)
+ module_info = scan.module_info_from_dotted_name(obj_module)
+
+ module = module_info.getModule()
+ if context is not None:
+ grokcore.component.context.set(module, context)
+ if templates is not None:
+ module.__grok_templates__ = templates
+ config = ConfigurationMachine()
+ result = zcml.the_multi_grokker.grok(name, component,
+ module_info=module_info,
+ config=config)
+ config.execute_actions()
+ return result
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# make this directory a package
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapter.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,36 @@
+"""
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+ >>> home = IHome(cave)
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+
+ >>> fireplace = IFireplace(cave)
+ >>> IFireplace.providedBy(fireplace)
+ True
+ >>> isinstance(fireplace, Fireplace)
+ True
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+ pass
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome)
+
+class IFireplace(interface.Interface):
+ pass
+
+class Fireplace(grok.Adapter):
+ grok.implements(IFireplace, IHome)
+ grok.provides(IFireplace)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/adapterdecorator.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,90 @@
+"""
+ >>> grok.testing.grok(__name__)
+ >>>
+ >>> cave = Cave()
+ >>> home = IHome(cave)
+ >>> home.id
+ u'default'
+ >>> IHome.providedBy(home)
+ True
+ >>>
+ >>> isinstance(home, Home)
+ True
+ >>> morehome = IMoreHome(cave)
+ >>> morehome.id
+ u'default'
+ >>> IHome.providedBy(morehome)
+ True
+ >>> isinstance(morehome, Home)
+ True
+ >>> yetanotherhome = IYetAnotherHome(cave)
+ >>> IHome.providedBy(yetanotherhome)
+ True
+ >>> isinstance(yetanotherhome, Home)
+ True
+ >>> yetanotherhome.id
+ u'default'
+
+ >>> from grokcore.component.tests.adapter import noarguments_fixture
+ Traceback (most recent call last):
+ ...
+ GrokImportError: @grok.adapter requires at least one argument.
+
+ >>> from grokcore.component.tests.adapter import functionasargument_fixture
+ Traceback (most recent call last):
+ ...
+ GrokImportError: @grok.adapter requires at least one argument.
+
+ >>> from zope.component import getAdapter
+ >>> home = getAdapter(cave, IHome, name='home')
+ >>> home.id
+ u'secondary'
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class IDummy(interface.Interface):
+ pass
+
+class ICave(interface.Interface):
+ pass
+
+class IHome(interface.Interface):
+ pass
+
+class IMoreHome(interface.Interface):
+ pass
+
+class IYetAnotherHome(interface.Interface):
+ pass
+
+class Cave(grok.Context):
+ grok.implements(ICave)
+ pass
+
+class Home(object):
+ grok.implements(IHome)
+
+ def __init__(self, id=u"default"):
+ self.id = id
+
+ at grok.adapter(Cave)
+ at grok.implementer(IHome)
+def home_for_cave(cave):
+ return Home()
+
+ at grok.adapter(ICave)
+ at grok.implementer(IMoreHome)
+def more_home_for_cave(cave):
+ return Home()
+
+ at grok.implementer(IYetAnotherHome)
+def yet_another_home_for_cave(cave):
+ return Home()
+
+ at grok.adapter(Cave, name=u"home")
+ at grok.implementer(IHome)
+def home_for_cave_named(cave):
+ return Home(u"secondary")
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/alphabetical.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,26 @@
+"""
+Grok does not depend on the alphabetical order:
+
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = ZCave()
+ >>> home = IHome(cave)
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class ZCave(grok.Context):
+ """we call this `ZCave` because we want to test that we do not
+ depend on alphabetical order"""
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontext.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,29 @@
+"""
+Explicit class-level context in case of multiple models:
+
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+ >>> home = IHome(cave)
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+ pass
+
+class Club(grok.Context):
+ pass
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome)
+ grok.context(Cave)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextimported.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+"""
+Explicit class-level context for an imported model:
+
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+ >>> painting = IPainting(cave)
+
+ >>> IPainting.providedBy(painting)
+ True
+ >>> isinstance(painting, Painting)
+ True
+
+"""
+import grokcore.component as grok
+from grokcore.component.tests.adapter.adapter import Cave
+from zope import interface
+
+class IPainting(interface.Interface):
+ pass
+
+class Painting(grok.Adapter):
+ grok.implements(IPainting)
+ grok.context(Cave)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,11 @@
+"""
+You can't call grok.context multiple times on class level:
+
+ >>> import grokcore.component.tests.adapter.classcontextmultiple_fixture
+ Traceback (most recent call last):
+ ...
+ GrokImportError: The 'context' directive can only be called once per
+ class or module.
+
+"""
+
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classcontextmultiple_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,11 @@
+import grokcore.component as grok
+
+class Cave(grok.Context):
+ pass
+
+class Club(grok.Context):
+ pass
+
+class Anything(object):
+ grok.context(Cave)
+ grok.context(Club)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/classorinterface.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,46 @@
+"""
+You can only use `grok.context` with interfaces or classes and not
+with anything else:
+
+ >>> function_context()
+ Traceback (most recent call last):
+ ...
+ GrokImportError: The 'context' directive can only be called with a class or an interface.
+
+ >>> string_context()
+ Traceback (most recent call last):
+ ...
+ GrokImportError: The 'context' directive can only be called with a class or an interface.
+
+ >>> module_context()
+ Traceback (most recent call last):
+ ...
+ GrokImportError: The 'context' directive can only be called with a class or an interface.
+
+ >>> instance_context()
+ Traceback (most recent call last):
+ ...
+ GrokImportError: The 'context' directive can only be called with a class or an interface.
+
+"""
+import grokcore.component as grok
+
+def function_context():
+ def a():
+ pass
+
+ class FunctionContext(object):
+ grok.context(a)
+
+def string_context():
+ class StringContext(object):
+ grok.context('string')
+
+def module_context():
+ class ModuleContext(object):
+ grok.context(grok)
+
+def instance_context():
+ obj = object()
+ class InstanceContext(object):
+ grok.context(obj)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/conflict.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,39 @@
+"""
+Registering two adapters for the same target interface should provoke
+a conflict, even if the interface is guessed (instead of being
+explicitly declared with grok.provides):
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ ConfigurationConflictError: Conflicting configuration actions
+ For: ('adapter', <InterfaceClass grokcore.component.tests.adapter.conflict.ICave>, <InterfaceClass grokcore.component.tests.adapter.conflict.IDecoration>, u'')
+
+"""
+import grokcore.component as grok
+from zope.interface import Interface
+
+class ICave(Interface):
+ pass
+
+class IDecoration(Interface):
+ pass
+
+class ICaveCleaning(Interface):
+ pass
+
+class Cave(object):
+ grok.implements(ICave)
+
+
+class ImplicitProvides(grok.Adapter):
+ """Here the provided interface is guessed because the class only
+ implements one interface."""
+ grok.context(ICave)
+ grok.implements(IDecoration)
+
+class ExplicitProvides(grok.Adapter):
+ """Here the provided interface is specific explicitly."""
+ grok.context(ICave)
+ grok.implements(IDecoration, ICaveCleaning)
+ grok.provides(IDecoration)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functionasargument_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,10 @@
+import grokcore.component as grok
+from zope import interface
+
+class IDummy(interface.Interface):
+ pass
+
+ at grok.adapter
+ at grok.implementer(IDummy)
+def decorator_called_with_function_as_argument(cave):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/functioncontext.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,32 @@
+"""
+You can't call grok.context from a function:
+
+ >>> func()
+ Traceback (most recent call last):
+ ...
+ GrokImportError: The 'context' directive can only be used on class or
+ module level.
+
+You can't call grok.context from a method either:
+
+ >>> SomeClass().meth()
+ Traceback (most recent call last):
+ ...
+ GrokImportError: The 'context' directive can only be used on class or
+ module level.
+
+"""
+import grokcore.component as grok
+from grokcore.component.tests.adapter.adapter import Cave
+
+def func():
+ """We don't allow calling `grok.context` from anything else than a
+ module or a class"""
+ grok.context(Cave)
+
+class SomeClass(object):
+
+ def meth(self):
+ """We don't allow calling `grok.context` from anything else
+ than a module or a class"""
+ grok.context(Cave)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/globaladapter.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,149 @@
+"""
+ >>> grok.testing.grok(__name__)
+ >>> from zope.component import getAdapter, getMultiAdapter
+
+ >>> cave = Cave()
+ >>> fireplace = Fireplace()
+
+ >>> home = IHome(cave)
+ >>> home.id
+ u'one'
+
+ >>> home = getAdapter(cave, IHome, name=u"two")
+ >>> home.id
+ u'two'
+
+ >>> home = getAdapter(cave, IHome, name=u"three")
+ >>> home.id
+ u'three'
+
+ >>> home = getAdapter(cave, IHome, name=u"four")
+ >>> home.id
+ u'four'
+
+ >>> home = getAdapter(fireplace, IHome, name=u"five")
+ >>> home.id
+ u'five'
+
+ >>> home = getMultiAdapter((cave, fireplace), IHome)
+ >>> home.id
+ u'six'
+
+ >>> home = getAdapter(fireplace, IHome, name=u'seven')
+ >>> home.id
+ u'seven-a'
+
+ >>> home = getMultiAdapter((cave, fireplace), IHome, name=u'seven')
+ >>> home.id
+ u'seven-b'
+
+ >>> garage = getAdapter(cave, IGarage, name='named_garage_factory_name')
+ >>> garage.id
+ u"I'm a garage"
+
+ >>> garage = getAdapter(cave, IGarage)
+ >>> garage.id
+ u"I'm a garage"
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+from zope.interface import implementer
+
+
+class Cave(grok.Context):
+ pass
+
+
+class Fireplace(object):
+ pass
+
+
+class IHome(interface.Interface):
+ pass
+
+
+class Home(object):
+ grok.implements(IHome)
+
+ def __init__(self, id):
+ self.id = id
+
+
+class CaveHomeFactory(object):
+ grok.implements(IHome)
+
+ def __init__(self, id):
+ self.id = id
+
+ def __call__(self, context):
+ return Home(self.id)
+
+
+class CaveFireplaceHomeFactory(object):
+
+ def __init__(self, id):
+ self.id = id
+
+ def __call__(self, cave, fireplace):
+ return Home(self.id)
+
+
+factory1 = CaveHomeFactory(u"one")
+factory2 = CaveHomeFactory(u"two")
+factory3 = CaveHomeFactory(u"three")
+factory4 = CaveHomeFactory(u"four")
+factory5 = CaveHomeFactory(u"five")
+factory6 = CaveFireplaceHomeFactory(u"six")
+factory7a = CaveHomeFactory(u"seven-a")
+factory7b = CaveFireplaceHomeFactory(u"seven-b")
+
+# make some direct assertions
+
+implementer(IHome)(factory3)
+implementer(IHome)(factory4)
+implementer(IHome)(factory5)
+implementer(IHome)(factory6)
+implementer(IHome)(factory7a)
+implementer(IHome)(factory7b)
+
+grok.adapter(Fireplace)(factory5)
+grok.adapter(Fireplace)(factory7a)
+grok.adapter(Cave, Fireplace)(factory7b)
+
+# should accept single value for adapts
+grok.global_adapter(factory1, Cave, IHome)
+# should accept tuple for adapts
+grok.global_adapter(factory2, (Cave,), IHome, name=u"two")
+# should look at the provided interface
+grok.global_adapter(factory3, Cave, name=u"three")
+# should pick the canonical context
+grok.global_adapter(factory4, name=u"four")
+# should use __component_adapts__
+grok.global_adapter(factory5, name=u"five")
+# should work as multi-adapter
+grok.global_adapter(factory6, (Cave, Fireplace,))
+# should use __component_adapts__ adapting one object
+grok.global_adapter(factory7a, name=u"seven")
+# should use __component_adapts__ adaping two objects
+grok.global_adapter(factory7b, name=u"seven")
+
+
+class IGarage(interface.Interface):
+ pass
+
+
+class NamedGarageFactory(object):
+ grok.implements(IGarage)
+ grok.name('named_garage_factory_name')
+
+ def __init__(self, context):
+ self.id = u"I'm a garage"
+
+implementer(IGarage)(NamedGarageFactory)
+
+# should register a named adapter
+grok.global_adapter(NamedGarageFactory, Cave, IGarage)
+# should override component's name
+grok.global_adapter(NamedGarageFactory, Cave, IGarage, name=u'')
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsmany.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+Subclasses of grok.Adapter and grok.MultiAdapter must implement exactly one
+interface:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.adapter.implementsmany.Home'> is implementing
+ more than one interface (use grok.provides to specify which one to use).
+"""
+import grokcore.component as grok
+
+from zope import interface
+
+class Cave(grok.Context):
+ pass
+
+class IHome(interface.Interface):
+ pass
+
+class IFireplace(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome, IFireplace)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnone.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,17 @@
+"""
+Subclasses of grok.Adapter and grok.MultiAdapter must implement exactly one
+interface:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.adapter.implementsnone.Home'> must
+ implement at least one interface (use grok.implements to specify).
+"""
+import grokcore.component as grok
+
+class Cave(grok.Context):
+ pass
+
+class Home(grok.Adapter):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/implementsnonemulti.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,17 @@
+"""
+Subclasses of grok.Adapter and grok.MultiAdapter must implement exactly one
+interface:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.adapter.implementsnonemulti.Home'> must
+ implement at least one interface (use grok.implements to specify).
+"""
+import grokcore.component as grok
+
+class Cave(grok.Context):
+ pass
+
+class Home(grok.MultiAdapter):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+Imported model and adapter won't be grokked:
+
+ >>> import grokcore.component as grok
+ >>> grok.testing.grok(__name__)
+ >>> from grokcore.component.tests.adapter.adapter import IHome
+ >>> cave = Cave()
+ >>> home = IHome(cave)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Could not adapt', <grokcore.component.tests.adapter.adapter.Cave object at ...>, <InterfaceClass grokcore.component.tests.adapter.adapter.IHome>)
+
+"""
+from grokcore.component.tests.adapter.adapter import Cave, Home
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/importedmodel2.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+"""
+Grok error because import model doesn't count as context:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: No module-level context for
+ <class 'grokcore.component.tests.adapter.importedmodel2.Painting'>,
+ please use the 'context' directive.
+
+"""
+import grokcore.component as grok
+from grokcore.component.tests.adapter.adapter import Cave
+from zope import interface
+
+class IPainting(interface.Interface):
+ pass
+
+class Painting(grok.Adapter):
+ """
+ Grokking of this should fail because there's no model (only an
+ imported one which doesn't count).
+ """
+ grok.implements(IPainting)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interface.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,41 @@
+"""
+You can also specify interfaces instead of classes with
+`grok.context` (class-level):
+
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+ >>> home = IHome(cave)
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+
+ >>> hole = Hole()
+ >>> home = IHome(hole)
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class ICave(interface.Interface):
+ pass
+
+class Cave(grok.Context):
+ grok.implements(ICave)
+
+class Hole(grok.Context):
+ grok.implements(ICave)
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome)
+ grok.context(ICave)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/interfacemodule.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,42 @@
+"""
+You can also specify interfaces instead of classes with
+`grok.context` (module-level):
+
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+ >>> home = IHome(cave)
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+
+ >>> hole = Hole()
+ >>> home = IHome(hole)
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class ICave(interface.Interface):
+ pass
+
+class Cave(grok.Context):
+ grok.implements(ICave)
+
+class Hole(grok.Context):
+ grok.implements(ICave)
+
+grok.context(ICave)
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontext.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,30 @@
+"""
+Explicit module-level context in case of multiple models:
+
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+ >>> home = IHome(cave)
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+ pass
+
+class Club(grok.Context):
+ pass
+
+grok.context(Cave)
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextimported.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+Explicit module-level context for an imported model:
+
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+ >>> painting = IPainting(cave)
+
+ >>> IPainting.providedBy(painting)
+ True
+ >>> isinstance(painting, Painting)
+ True
+
+"""
+import grokcore.component as grok
+from grokcore.component.tests.adapter.adapter import Cave
+from zope import interface
+
+grok.context(Cave)
+
+class IPainting(interface.Interface):
+ pass
+
+class Painting(grok.Adapter):
+ grok.implements(IPainting)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,10 @@
+"""
+You can't call grok.context multiple times on module level:
+
+ >>> import grokcore.component.tests.adapter.modulecontextmultiple_fixture
+ Traceback (most recent call last):
+ ...
+ GrokImportError: The 'context' directive can only be called once per
+ class or module.
+
+"""
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/modulecontextmultiple_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,11 @@
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+ pass
+
+class Club(grok.Context):
+ pass
+
+grok.context(Cave)
+grok.context(Club)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadapter.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,91 @@
+"""
+Multi-Adapters are supported by subclassing grok.MultiAdapter, giving
+multiple arguments to grok.adapts, and supplying a matching
+__init__():
+
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+ >>> fireplace = Fireplace()
+
+ >>> from zope import component
+ >>> home = component.getMultiAdapter((cave, fireplace))
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+ >>> home.cave is cave
+ True
+ >>> home.fireplace is fireplace
+ True
+
+This also works for named adapters using grok.name:
+
+ >>> home = component.getMultiAdapter((cave, fireplace), name='home2')
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home2)
+ True
+ >>> home.cave is cave
+ True
+ >>> home.fireplace is fireplace
+ True
+
+Multiadapters that implement more than one interface can use grok.provides to
+specify the one to use:
+
+ >>> home = component.getMultiAdapter((cave, fireplace), name='home3')
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home3)
+ True
+ >>> home.cave is cave
+ True
+ >>> home.fireplace is fireplace
+ True
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+ pass
+
+class Fireplace(grok.Context):
+ pass
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.MultiAdapter):
+ grok.adapts(Cave, Fireplace)
+ grok.implements(IHome)
+
+ def __init__(self, cave, fireplace):
+ self.cave = cave
+ self.fireplace = fireplace
+
+class Home2(grok.MultiAdapter):
+ grok.adapts(Cave, Fireplace)
+ grok.implements(IHome)
+ grok.name('home2')
+
+ def __init__(self, cave, fireplace):
+ self.cave = cave
+ self.fireplace = fireplace
+
+class IFireplace(interface.Interface):
+ pass
+
+class Home3(grok.MultiAdapter):
+ grok.adapts(Cave, Fireplace)
+ grok.implements(IHome, IFireplace)
+ grok.provides(IHome)
+ grok.name('home3')
+
+ def __init__(self, cave, fireplace):
+ self.cave = cave
+ self.fireplace = fireplace
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiadaptsnone.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,18 @@
+"""
+Subclasses of grok.MultiAdapter must declare what they adapt, using grok.adapts:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.adapter.multiadaptsnone.Home'>
+ must specify which contexts it adapts (use the 'adapts' directive to specify).
+"""
+import grokcore.component as grok
+
+from zope import interface
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.MultiAdapter):
+ grok.implements(IHome)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/multiple.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+Multiple models lead to ambiguity:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: Multiple possible contexts for
+ <class 'grokcore.component.tests.adapter.multiple.Home'>, please use the
+ 'context' directive.
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+ pass
+
+class Club(grok.Context):
+ pass
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/namedadapter.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,31 @@
+"""
+You can register a named adapter by using grok.name:
+
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+ >>> home = IHome(cave)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Could not adapt', <grokcore.component.tests.adapter.namedadapter.Cave object at 0x...>, <InterfaceClass grokcore.component.tests.adapter.namedadapter.IHome>)
+
+ >>> from zope.component import getAdapter
+ >>> home = getAdapter(cave, IHome, name='home')
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class Cave(grok.Context):
+ pass
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome)
+ grok.name('home')
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/noarguments_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,10 @@
+import grokcore.component as grok
+from zope import interface
+
+class IDummy(interface.Interface):
+ pass
+
+ at grok.adapter()
+ at grok.implementer(IDummy)
+def decorator_called_with_no_arguments(cave):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/nomodel.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,19 @@
+"""
+If no model can be found in the module, we get an error:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: No module-level context for
+ <class 'grokcore.component.tests.adapter.nomodel.Home'>, please use the
+ 'context' directive.
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/oldstyleclass.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+Old-style classes are also supported:
+
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+ >>> home = IHome(cave)
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+"""
+import grokcore.component as grok
+from zope import interface
+
+class Cave:
+ pass
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome)
+ grok.context(Cave)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/order.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,26 @@
+"""
+If the model is defined after the adapter, it should still be grokked
+properly:
+
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+ >>> home = IHome(cave)
+
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IHome(interface.Interface):
+ pass
+
+class Home(grok.Adapter):
+ grok.implements(IHome)
+
+class Cave(grok.Context):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/adapter/providerdecorator.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,44 @@
+"""
+ >>> grok.testing.grok(__name__)
+
+ >>> IMarker.providedBy(not_marked)
+ False
+ >>> IMarker.providedBy(marked)
+ True
+ >>> IMarker.providedBy(double_marked)
+ True
+
+ >>> IMarker2.providedBy(not_marked)
+ False
+ >>> IMarker2.providedBy(marked)
+ False
+ >>> IMarker2.providedBy(double_marked)
+ True
+
+ >>> marked()
+ 123
+
+ >>> double_marked()
+ 234
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class IMarker(interface.Interface):
+ pass
+
+class IMarker2(interface.Interface):
+ pass
+
+ at grok.provider(IMarker)
+def marked():
+ return 123
+
+ at grok.provider(IMarker, IMarker2)
+def double_marked():
+ return 234
+
+def not_marked():
+ return 456
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/api.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,17 @@
+The grokcore.component API
+==========================
+
+The grokcore.component API is described by the
+``grokcore.component.interfaces.IGrokcoreComponentAPI`` interface.
+When you do
+
+ >>> from grokcore.component import *
+
+only those objects described in that API interface are imported into
+your local namespace. In other words, if we take the list of things
+that have been imported and subtract the things that have been defined
+in the API interface, we'll end with pretty much nothing:
+
+ >>> from grokcore.component.interfaces import IGrokcoreComponentAPI
+ >>> sorted(set(locals()) - set(IGrokcoreComponentAPI))
+ ['IGrokcoreComponentAPI', '__builtins__', '__file__']
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+"""
+ >>> import grokcore.component.tests.directive.argumenterror_fixture
+ Traceback (most recent call last):
+ ...
+ TypeError: name takes exactly 1 argument (3 given)
+
+"""
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/argumenterror_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,4 @@
+import grokcore.component as grok
+
+class Foo(object):
+ grok.name('too', 'many', 'arguments')
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/directive/multipletimes.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,46 @@
+"""
+Since grok.global_utility is a MultipleTimesDirective, there is a list of
+GlobalUtilityInfo objects annotated on the module.
+
+
+ >>> from martian import scan
+ >>> import grokcore.component as grok
+ >>> from grokcore.component.tests.directive import multipletimes
+ >>> guis = grok.global_utility.bind().get(multipletimes)
+ >>> len(guis)
+ 2
+
+ >>> factory, provides, name, direct = guis[0]
+ >>> factory
+ <class 'grokcore.component.tests.directive.multipletimes.Club'>
+ >>> provides
+ <InterfaceClass grokcore.component.tests.directive.multipletimes.IClub>
+ >>> name
+ 'foo'
+
+ >>> factory, provides, name, direct = guis[1]
+ >>> factory
+ <class 'grokcore.component.tests.directive.multipletimes.Cave'>
+ >>> provides is None
+ True
+ >>> name
+ u''
+
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+ pass
+
+class ICave(interface.Interface):
+ pass
+
+class Club(object):
+ grok.implements(IClub)
+
+class Cave(object):
+ grok.implements(ICave)
+
+grok.global_utility(Club, provides=IClub, name='foo')
+grok.global_utility(Cave)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,35 @@
+"""
+ at grok.subscribe can only be used on module level:
+
+ >>> function_context()
+ Traceback (most recent call last):
+ ...
+ GrokImportError: @grok.subscribe can only be used on module level.
+
+ >>> class_context()
+ Traceback (most recent call last):
+ ...
+ GrokImportError: @grok.subscribe can only be used on module level.
+
+
+ at grok.subscribe can not be called without arguments:
+
+ >>> import grokcore.component.tests.event.errorconditions_fixture
+ Traceback (most recent call last):
+ ...
+ GrokImportError: @grok.subscribe requires at least one argument.
+
+"""
+import grokcore.component as grok
+from zope.component.interfaces import IObjectEvent
+
+def function_context():
+ @grok.subscribe(grok.Context, IObjectEvent)
+ def subscriber():
+ pass
+
+def class_context():
+ class Wrapper:
+ @grok.subscribe(grok.Context, IObjectEvent)
+ def subscriber(self):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/errorconditions_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,5 @@
+import grokcore.component as grok
+
+ at grok.subscribe()
+def subscriber():
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/provideHandler.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,28 @@
+"""
+When you use the @grokcore.component.subscribe decorator, you can also
+use zope.component.provideHandler to register the subscriber. This
+can be useful for unittests where you may not want to grok everything
+in a module but just enable certain components.
+
+ >>> from zope.component import provideHandler
+ >>> provideHandler(mammothAdded)
+
+ >>> manfred = Mammoth('Manfred')
+ >>> import zope.event
+ >>> zope.event.notify(ObjectEvent(manfred))
+ >>> mammoths
+ ['Manfred']
+
+"""
+import grokcore.component as grok
+from zope.component.interfaces import IObjectEvent, ObjectEvent
+
+class Mammoth(object):
+ def __init__(self, name):
+ self.name = name
+
+mammoths = []
+
+ at grok.subscribe(Mammoth, IObjectEvent)
+def mammothAdded(mammoth, event):
+ mammoths.append(mammoth.name)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/event/subscriber.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,36 @@
+"""
+You can subscribe to events using the @grok.subscribe decorator:
+
+ >>> grok.testing.grok(__name__)
+ >>> manfred = Mammoth('Manfred')
+ >>> zope.event.notify(ObjectEvent(manfred))
+ >>> mammoths
+ ['Manfred']
+ >>> mammoths2
+ ['Manfred']
+
+The decorated event handling function can also be called directly:
+
+ >>> mammothAdded(Mammoth('Max'),None)
+ >>> mammoths
+ ['Manfred', 'Max']
+
+"""
+import zope.event
+import grokcore.component as grok
+from zope.component.interfaces import IObjectEvent, ObjectEvent
+
+class Mammoth(object):
+ def __init__(self, name):
+ self.name = name
+
+mammoths = []
+mammoths2 = []
+
+ at grok.subscribe(Mammoth, IObjectEvent)
+def mammothAdded(mammoth, event):
+ mammoths.append(mammoth.name)
+
+ at grok.subscribe(Mammoth, IObjectEvent)
+def mammothAddedInstance(mammoth, event):
+ mammoths2.append(mammoth.name)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grok_component.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,42 @@
+Test grok_component() in an ordinary doctest.
+
+We already have tests for grok_component(), but these were placed
+inside a module. We will now test grok_component() in a pure doctest
+context. This used to demonstrate an error in martian when dealing
+with the __builtin__ module (fixed in martian 0.9.2).
+
+grokcore.component.testing.grok_component() can be used to grok individual
+components within a doctest, such as adapters. It sets up just enough
+context for some grokking to work, though more complicated grokkers
+which need module context (such as view grokkers) might not work.
+
+This defines the object we want to provide an adapter for::
+
+ >>> class Bar(object):
+ ... pass
+
+This is the interface that we want to adapt to::
+
+ >>> from zope.interface import Interface
+ >>> class IFoo(Interface):
+ ... pass
+
+This is the adapter itself::
+
+ >>> import grokcore.component as grok
+ >>> class MyAdapter(grok.Adapter):
+ ... grok.provides(IFoo)
+ ... grok.context(Bar)
+
+Now we will register the adapter using grok_component()::
+
+ >>> from grokcore.component.testing import grok, grok_component
+ >>> grok('grokcore.component.meta')
+ >>> grok_component('MyAdapter', MyAdapter)
+ True
+
+The adapter should now be available::
+
+ >>> adapted = IFoo(Bar())
+ >>> isinstance(adapted, MyAdapter)
+ True
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,42 @@
+"""
+A Grokker can declare that scanning should continue, so that other Grokkers can
+still perform actions on the grokked components.
+
+Here we define AlphaGrokker which has higher priority than BetaGrokker but does
+not block BetaGrokker from picking up the same component::
+
+ >>> import grokcore.component as grok
+ >>> grok.testing.grok(__name__)
+
+In the fixture there is AlphaBetaSub that inherits from both Alpha and Beta.
+Thus, both Grokkers are executed, with AlphaGrokker coming before BetaGrokker::
+
+ >>> grok.testing.grok('grokcore.component.tests.grokker.continue_scanning_fixture')
+ alpha
+ beta
+
+"""
+import martian
+
+
+class Alpha(object):
+ pass
+
+class Beta(object):
+ pass
+
+class AlphaGrokker(martian.ClassGrokker):
+ martian.component(Alpha)
+ martian.priority(1) # we need to go before BetaGrokker
+
+ def grok(self, name, factory, module_info, config, **kw):
+ print "alpha"
+ return True
+
+class BetaGrokker(martian.ClassGrokker):
+ martian.component(Beta)
+
+ def grok(self, name, factory, module_info, config, **kw):
+ print "beta"
+ return True
+
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/continue_scanning_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,4 @@
+from grokcore.component.tests.grokker.continue_scanning import Alpha, Beta
+
+class AlphaBetaSub(Alpha, Beta):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/grokcomponent.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,61 @@
+"""
+
+Let's first grok the meta module to define some basic grokkers::
+
+ >>> import grokcore.component as grok
+ >>> grok.testing.grok('grokcore.component.meta')
+
+It is possible to grok an individual component. Let's define an adapter::
+
+ >>> from zope.interface import Interface
+ >>> class IMyInterface(Interface):
+ ... pass
+ >>> class SomeClass(object):
+ ... pass
+ >>> class MyAdapter(grok.Adapter):
+ ... grok.provides(IMyInterface)
+ ... grok.context(SomeClass)
+
+To grok this adapter, you can simply write this::
+
+ >>> grok.testing.grok_component('MyAdapter', MyAdapter)
+ True
+
+We can now use the adapter::
+
+ >>> instance = SomeClass()
+ >>> adapter = IMyInterface(instance)
+ >>> isinstance(adapter, MyAdapter)
+ True
+
+We can use grok_component with only two arguments because we know the
+adapter grokker is not looking for more. Sometimes we need to supply
+an extra argument however::
+
+ >>> class ISecondInterface(Interface):
+ ... pass
+ >>> class SecondAdapter(grok.Adapter):
+ ... grok.provides(ISecondInterface)
+
+This adapter does not supply its own context. Trying to do what we did
+before will therefore fail::
+
+ >>> grok.testing.grok_component('SecondAdapter', SecondAdapter)
+ Traceback (most recent call last):
+ ...
+ GrokError: No module-level context for <class 'grokcore.component.tests.grokker.grokcomponent.SecondAdapter'>, please use the 'context' directive.
+
+So we need to supply the context ourselves::
+
+ >>> grok.testing.grok_component('SecondAdapter', SecondAdapter, context=SomeClass)
+ True
+
+Now we can use the SecondAdapter as well::
+
+ >>> adapter = ISecondInterface(instance)
+ >>> isinstance(adapter, SecondAdapter)
+ True
+
+The next optional argument is module_info and the final argument is
+templates.
+"""
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,27 @@
+"""
+
+We define a grokker AlphaGrokker for a component called Alpha. We first need to
+grok the module defining the grokkers, in order to get them registered.
+
+Usually this would be triggered from a meta.zcml in a package, that would grok
+the module containing the grokkers (e.g. meta.py).
+
+We do it manually now::
+
+ >>> import grokcore.component as grok
+ >>> grok.testing.grok('grokcore.component.tests.grokker.onlyonce_fixture._meta')
+
+This _meta.py module then will be grokked again during 'normal' grok time. Grok
+will not re-register the grokkers as this could have unwanted side-effects. It
+will grok the components of course.
+
+NOTE: the module is called _meta to make sure it is grokked (although its
+grokker registration should be ignored) before the other files. The modules are
+picked up in alphabetical order.
+
+To simulate this, we grok the whole package::
+
+ >>> grok.testing.grok('grokcore.component.tests.grokker.onlyonce_fixture')
+ alpha
+
+"""
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# fixture package
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/_meta.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+import martian
+from component import Alpha
+
+class AlphaGrokker(martian.ClassGrokker):
+ martian.component(Alpha)
+
+ def grok(self, name, factory, module_info, **kw):
+ print "alpha"
+ return True
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/component.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,4 @@
+import grokcore.component as grok
+
+class Alpha(object):
+ grok.baseclass()
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/onlyonce_fixture/implementation.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,4 @@
+from component import Alpha
+
+class AlphaSub(Alpha):
+ pass
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,55 @@
+"""
+We define grokkers for the three base classes Alpha, Beta, and Gamma with different
+priorities:
+
+- AlphaGrokker with priority 0 (default)
+- BetaGrokker with priority 1
+- GammaGrokker with priority -1
+
+ >>> import grokcore.component as grok
+ >>> grok.testing.grok(__name__)
+
+We grok a module that implements subclasses for Alpha, Beta, and Gamma and our
+grokkers get executed in the order of priority (highest first)::
+
+ >>> grok.testing.grok('grokcore.component.tests.grokker.priority_fixture')
+ beta
+ alpha
+ gamma
+
+"""
+import martian
+
+
+class Alpha(object):
+ pass
+
+
+class Beta(object):
+ pass
+
+class Gamma(object):
+ pass
+
+class AlphaGrokker(martian.ClassGrokker):
+ martian.component(Alpha)
+
+ def grok(self, name, factory, module_info, **kw):
+ print "alpha"
+ return True
+
+class BetaGrokker(martian.ClassGrokker):
+ martian.component(Beta)
+ martian.priority(1)
+
+ def grok(self, name, factory, module_info, **kw):
+ print "beta"
+ return True
+
+class GammaGrokker(martian.ClassGrokker):
+ martian.component(Gamma)
+ martian.priority(-1)
+
+ def grok(self, name, factory, module_info, **kw):
+ print "gamma"
+ return True
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/grokker/priority_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,10 @@
+import grokcore.component.tests.grokker.priority
+
+class AlphaSub(grokcore.component.tests.grokker.priority.Alpha):
+ pass
+
+class BetaSub(grokcore.component.tests.grokker.priority.Beta):
+ pass
+
+class GammaSub(grokcore.component.tests.grokker.priority.Gamma):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+#
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,22 @@
+"""
+We expect the module-level grok.context to be inherited by subclasses of
+an adapter that is associated with this directive. FooAdapter is such
+an adapter, defined in inherit_fixture. In this module we've inherited
+from it.
+
+Explicit module-level context for an imported model:
+
+ >>> grok.testing.grok(__name__)
+
+ >>> from zope import component
+ >>> o = component.getAdapter(inherit_fixture.Foo(), inherit_fixture.IAnder,
+ ... name='bar')
+ >>> isinstance(o, BarAdapter)
+ True
+"""
+import grokcore.component as grok
+from grokcore.component.tests.inherit import inherit_fixture
+
+# FooAdapter has a module-level grok.context to associate it
+class BarAdapter(inherit_fixture.FooAdapter):
+ grok.name('bar')
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/inherit/inherit_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+import grokcore.component
+from zope.interface import Interface
+
+class Foo(grokcore.component.Context):
+ pass
+
+grokcore.component.context(Foo)
+
+class IAnder(Interface):
+ pass
+
+class FooAdapter(grokcore.component.Adapter):
+ grokcore.component.provides(IAnder)
+
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+#
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/arg_orderdirective.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,42 @@
+"""
+If the grok.order directive is present with arguments, sorting will be
+done by the order specified.
+
+ >>> from grokcore.component import sort_components
+
+ >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
+ >>> sort_components(components)
+ [<...Fifth object at ...>,
+ <...Fourth object at ...>,
+ <...Third object at ...>,
+ <...Second object at ...>,
+ <...First object at ...>]
+
+You can use the key option:
+
+ >>> from operator import itemgetter
+
+ >>> components = [(1, First()), (2, Second()), (3, Third())]
+ >>> sort_components(components, key=itemgetter(1))
+ [(3, <...Third object at ...>),
+ (2, <...Second object at ...>),
+ (1, <...First object at ...>)]
+
+"""
+
+import grokcore.component as grok
+
+class First(object):
+ grok.order(5)
+
+class Second(object):
+ grok.order(4)
+
+class Third(object):
+ grok.order(3)
+
+class Fourth(object):
+ grok.order(2)
+
+class Fifth(object):
+ grok.order(1)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combined_orderdirective.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,34 @@
+"""
+
+If the grok.order directive is specified with other classes that don't
+have the order specified, then the order will be determined by first
+sorting on the order specified, and then by the definition order.
+
+ >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
+
+ >>> from grokcore.component import sort_components
+ >>> sort_components(components)
+ [<...Third object at ...>,
+ <...Fourth object at ...>,
+ <...Second object at ...>,
+ <...Fifth object at ...>,
+ <...First object at ...>]
+
+"""
+
+import grokcore.component as grok
+
+class First(object):
+ grok.order(2)
+
+class Second(object):
+ grok.order(1)
+
+class Third(object):
+ grok.order()
+
+class Fourth(object):
+ grok.order()
+
+class Fifth(object):
+ grok.order(1)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/combinednoorder_orderdirective.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,34 @@
+"""
+
+If the grok.order directive is specified with other classes that don't
+have the order specified, then the order will be determined by first
+sorting on the order specified, and then by the definition order.
+
+ >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
+
+ >>> from grokcore.component import sort_components
+ >>> sort_components(components)
+ [<...Fifth object at ...>,
+ <...Third object at ...>,
+ <...First object at ...>,
+ <...Fourth object at ...>,
+ <...Second object at ...>]
+
+"""
+
+import grokcore.component as grok
+
+class First(object):
+ grok.order()
+
+class Second(object):
+ grok.order(1)
+
+class Third(object):
+ pass
+
+class Fourth(object):
+ grok.order()
+
+class Fifth(object):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter1.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,35 @@
+"""
+
+The ordering works like so:
+1. Objects with explicit ordering
+ (if combined with objects with no ordering not specified, then the orderless
+ objects come first)
+2. Objects with same ordering get grouped by module import order
+3. Internal order within module
+4. If no ordering is specified by any objects, then objects are sorted
+ alphabetically by class name
+
+ >>> from inter2 import Four, Five, Six
+ >>> components = [One(), Two(), Three(), Four(), Five(), Six()]
+
+ >>> from grokcore.component import sort_components
+ >>> sort_components(components)
+ [<...Three object at ...>,
+ <...One object at ...>,
+ <...Five object at ...>,
+ <...Six object at ...>,
+ <...Four object at ...>,
+ <...Two object at ...>]
+
+"""
+
+import grokcore.component as grok
+
+class One(object):
+ grok.order()
+
+class Two(object):
+ grok.order(2)
+
+class Three(object):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/inter2.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+This module used by inter1 tests
+"""
+
+import grokcore.component as grok
+
+class Four(object):
+ grok.order(1)
+
+class Five(object):
+ pass
+
+class Six(object):
+ grok.order()
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/noarg_orderdirective.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,33 @@
+"""
+
+If the grok.order directive is present with no arguments, sorting will
+be done by definition order.
+
+ >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
+
+ >>> from grokcore.component import sort_components
+ >>> sort_components(components)
+ [<...First object at ...>,
+ <...Second object at ...>,
+ <...Third object at ...>,
+ <...Fourth object at ...>,
+ <...Fifth object at ...>]
+
+"""
+
+import grokcore.component as grok
+
+class First(object):
+ grok.order()
+
+class Second(object):
+ grok.order()
+
+class Third(object):
+ grok.order()
+
+class Fourth(object):
+ grok.order()
+
+class Fifth(object):
+ grok.order()
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/order/nodirective.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,31 @@
+"""
+
+If the grok.order directive is absent, sorting will be done by class
+name.
+
+ >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
+
+ >>> from grokcore.component import sort_components
+ >>> sort_components(components)
+ [<...Fifth object at ...>,
+ <...First object at ...>,
+ <...Fourth object at ...>,
+ <...Second object at ...>,
+ <...Third object at ...>]
+
+"""
+
+class First(object):
+ pass
+
+class Second(object):
+ pass
+
+class Third(object):
+ pass
+
+class Fourth(object):
+ pass
+
+class Fifth(object):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/decorator.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,41 @@
+"""
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave('sweet home')
+
+ >>> subscriptions = grok.querySubscriptions(cave, IActivity)
+ >>> subscriptions
+ [<grokcore.component.tests.subscriptions.decorator.DebuggingGrokcore object at ...>]
+
+ Subscription adapters are not registered as regular adapters:
+
+ >>> from zope import component
+ >>> component.queryAdapter(cave, IActivity)
+
+"""
+
+
+import grokcore.component as grok
+from zope import interface
+
+
+class Cave(grok.Context):
+
+ def __init__(self, name):
+ self.name = name
+
+
+class IActivity(interface.Interface):
+ pass
+
+
+class DebuggingGrokcore(object):
+
+ def __init__(self, where):
+ self.where = where
+
+
+ at grok.subscribe(Cave)
+ at grok.implementer(IActivity)
+def debugging(content):
+ return DebuggingGrokcore(content)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,98 @@
+"""
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave('Tilburg cave')
+ >>> martijn = Mammoth('Martijn')
+
+ You can query a subscriptions using multiple components. You will get
+ all subscriptions registered for office and cave (since office is a
+ base class of cave):
+
+ >>> subscriptions = grok.queryMultiSubscriptions((cave, martijn), IActivity)
+ >>> subscriptions
+ [<grokcore.component.tests.subscriptions.multisubscriptions.Sleep object at ...>,
+ <grokcore.component.tests.subscriptions.multisubscriptions.Food object at ...>,
+ <grokcore.component.tests.subscriptions.multisubscriptions.WritingCode object at ...>]
+
+ >>> _ = map(lambda s: s.do(), subscriptions)
+ Martijn is sleeping at Tilburg cave.
+ Martijn is feeding himself at Tilburg cave.
+ Martijn is writing code at Tilburg cave!
+
+
+ Now, Martijn goes to the office. You will only get subscriptions
+ registered for office:
+
+ >>> office = Office('Grok corp(r)(tm) headquarters')
+ >>> office_subscriptions = grok.queryMultiSubscriptions(
+ ... (office, martijn), IActivity)
+ >>> office_subscriptions
+ [<grokcore.component.tests.subscriptions.multisubscriptions.Sleep object at ...>]
+
+ >>> _ = map(lambda s: s.do(), office_subscriptions)
+ Martijn is sleeping at Grok corp(r)(tm) headquarters.
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+
+class Office(grok.Context):
+
+ def __init__(self, name):
+ self.name = name
+
+
+# All caves are a kind of office.
+class Cave(Office):
+ pass
+
+
+class Mammoth(grok.Context):
+
+ def __init__(self, name):
+ self.name = name
+
+
+class IActivity(interface.Interface):
+
+ def do():
+ """Do something.
+ """
+
+class Sleep(grok.MultiSubscription):
+ grok.implements(IActivity)
+ grok.adapts(Office, Mammoth)
+
+ def __init__(self, where, who):
+ self.where = where
+ self.who = who
+
+ def do(self):
+ print '%s is sleeping at %s.' % (self.who.name, self.where.name)
+
+
+class DayTimeActivity(grok.MultiSubscription):
+ grok.implements(IActivity)
+ grok.adapts(Cave, Mammoth)
+ grok.baseclass()
+
+ def __init__(self, where, who):
+ self.where = where
+ self.who = who
+
+ def do(self):
+ print 'nothing'
+
+
+class Food(DayTimeActivity):
+
+ def do(self):
+ print '%s is feeding himself at %s.' % (self.who.name, self.where.name)
+
+
+class WritingCode(DayTimeActivity):
+
+ def do(self):
+ print '%s is writing code at %s!' % (self.who.name, self.where.name)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,19 @@
+"""
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.subscriptions.multisubscriptions_no_adapts.CaveGardenRenovator'>
+ must specify which contexts it adapts (use the 'adapts' directive to specify).
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class IRenovate(interface.Interface):
+
+ def takedown():
+ pass
+
+class CaveGardenRenovator(grok.MultiSubscription):
+ grok.provides(IRenovate)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,20 @@
+"""
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.subscriptions.multisubscriptions_no_interface.CaveGardenRedecorator'>
+ must implement at least one interface (use grok.implements to specify).
+
+"""
+
+import grokcore.component as grok
+
+
+class Cave(grok.Context):
+ pass
+
+class Garden(grok.Context):
+ pass
+
+class CaveGardenRedecorator(grok.MultiSubscription):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,97 @@
+"""
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave('Tilburg cave')
+ >>> martijn = Mammoth('Martijn')
+
+ You can query a subscriptions using multiple components and sort them
+ using `grok.order` information:
+
+ >>> ordered_subscriptions = grok.queryOrderedMultiSubscriptions(
+ ... (cave, martijn), IActivity)
+ >>> ordered_subscriptions
+ [<grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cooking object at ...>,
+ <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Gardening object at ...>,
+ <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cleaning object at ...>]
+
+ >>> _ = map(lambda a: a.do(), ordered_subscriptions)
+ Martijn is cooking in Tilburg cave!
+ Martijn is growing pumpkins in Tilburg cave!
+ Martijn is cleaning the Tilburg cave.
+
+ Or choose not to:
+
+ >>> subscriptions = grok.queryMultiSubscriptions(
+ ... (cave, martijn), IActivity)
+
+ (still need to sort them on class name in order to have a working doctest)
+
+ >>> subscriptions = sorted(subscriptions, key=lambda s: s.__class__.__name__)
+ >>> subscriptions
+ [<grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cleaning object at ...>,
+ <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cooking object at ...>,
+ <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Gardening object at ...>]
+
+ >>> _ = map(lambda a: a.do(), subscriptions)
+ Martijn is cleaning the Tilburg cave.
+ Martijn is cooking in Tilburg cave!
+ Martijn is growing pumpkins in Tilburg cave!
+
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+
+class Cave(grok.Context):
+
+ def __init__(self, name):
+ self.name = name
+
+
+class Mammoth(grok.Context):
+
+ def __init__(self, name):
+ self.name = name
+
+
+class IActivity(interface.Interface):
+
+ def do():
+ """Do something.
+ """
+
+
+class DayTimeActivity(grok.MultiSubscription):
+ grok.provides(IActivity)
+ grok.adapts(Cave, Mammoth)
+ grok.baseclass()
+
+ def __init__(self, where, who):
+ self.where = where
+ self.who = who
+
+ def do(self):
+ print 'Doing nothing.'
+
+
+class Cleaning(DayTimeActivity):
+ grok.order(99)
+
+ def do(self):
+ print '%s is cleaning the %s.' % (self.who.name, self.where.name)
+
+
+class Cooking(DayTimeActivity):
+ grok.order(10)
+
+ def do(self):
+ print '%s is cooking in %s!' % (self.who.name, self.where.name)
+
+
+class Gardening(DayTimeActivity):
+ grok.order(15)
+
+ def do(self):
+ print '%s is growing pumpkins in %s!' % (self.who.name, self.where.name)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/ordered_subscriptions.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,71 @@
+"""
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave()
+
+ You can query the subscriptions and sort them with the information
+ provided by grok.order:
+
+ >>> ordered_subscriptions = grok.queryOrderedSubscriptions(cave, ICleaner)
+ >>> ordered_subscriptions
+ [<grokcore.component.tests.subscriptions.ordered_subscriptions.MondayCleaner object at ...>,
+ <grokcore.component.tests.subscriptions.ordered_subscriptions.WednesdayCleaner object at ...>,
+ <grokcore.component.tests.subscriptions.ordered_subscriptions.SaturdayCleaner object at ...>]
+
+ >>> _ = map(lambda s: s.work(), ordered_subscriptions)
+ Monday cleaning!
+ Wednesday cleaning!
+ Saturday cleaning!
+
+ If you use the regular query method, they won't be sorted:
+
+ >>> subscriptions = grok.querySubscriptions(cave, ICleaner)
+ >>> subscriptions
+ [<grokcore.component.tests.subscriptions.ordered_subscriptions.MondayCleaner object at ...>,
+ <grokcore.component.tests.subscriptions.ordered_subscriptions.SaturdayCleaner object at ...>,
+ <grokcore.component.tests.subscriptions.ordered_subscriptions.WednesdayCleaner object at ...>]
+
+ >>> _ = map(lambda s: s.work(), subscriptions)
+ Monday cleaning!
+ Saturday cleaning!
+ Wednesday cleaning!
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+
+class Cave(grok.Context):
+ pass
+
+
+class ICleaner(interface.Interface):
+
+ def work():
+ """Clean that cave.
+ """
+
+class MondayCleaner(grok.Subscription):
+ grok.implements(ICleaner)
+ grok.order(1)
+
+ def work(self):
+ print 'Monday cleaning!'
+
+
+class WednesdayCleaner(grok.Subscription):
+ grok.implements(ICleaner)
+ grok.order(3)
+
+ def work(self):
+ print 'Wednesday cleaning!'
+
+
+class SaturdayCleaner(grok.Subscription):
+ grok.implements(ICleaner)
+ grok.order(6)
+
+ def work(self):
+ print 'Saturday cleaning!'
+
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,58 @@
+"""
+ >>> grok.testing.grok(__name__)
+
+ >>> cave = Cave('sweet home')
+
+ >>> subscriptions = grok.querySubscriptions(cave, ICleaner)
+ >>> subscriptions
+ [<grokcore.component.tests.subscriptions.subscriptions.MondayCleaner object at ...>,
+ <grokcore.component.tests.subscriptions.subscriptions.SaturdayCleaner object at ...>,
+ <grokcore.component.tests.subscriptions.subscriptions.WednesdayCleaner object at ...>]
+
+ >>> _ = map(lambda s: s.work(), subscriptions)
+ Monday cleaning sweet home!
+ Saturday cleaning sweet home!
+ Wednesday cleaning sweet home!
+
+ Subscription adapters are not registered as regular adapters:
+
+ >>> component.queryAdapter(cave, ICleaner)
+
+"""
+
+import grokcore.component as grok
+from zope import interface, component
+
+
+class Cave(grok.Context):
+
+ def __init__(self, name):
+ self.name = name
+
+
+class ICleaner(interface.Interface):
+
+ def work():
+ """Clean that cave.
+ """
+
+class MondayCleaner(grok.Subscription):
+ grok.implements(ICleaner)
+
+ def work(self):
+ print 'Monday cleaning %s!' % self.context.name
+
+
+class WednesdayCleaner(grok.Subscription):
+ grok.provides(ICleaner)
+
+ def work(self):
+ print 'Wednesday cleaning %s!' % self.context.name
+
+
+class SaturdayCleaner(grok.Subscription):
+ grok.implements(ICleaner)
+
+ def work(self):
+ print 'Saturday cleaning %s!' % self.context.name
+
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_context.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,20 @@
+"""
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: No module-level context for
+ <class 'grokcore.component.tests.subscriptions.subscriptions_no_context.CaveProcessor'>,
+ please use the 'context' directive.
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class ITask(interface.Interface):
+
+ def finish():
+ pass
+
+class CaveProcessor(grok.Subscription):
+ grok.provides(ITask)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,17 @@
+"""
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.subscriptions.subscriptions_no_interface.CaveProcessor'>
+ must implement at least one interface (use grok.implements to specify).
+
+"""
+
+import grokcore.component as grok
+
+
+class Cave(grok.Context):
+ pass
+
+class CaveProcessor(grok.Subscription):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/test_grok.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,66 @@
+import re
+import unittest
+import traceback
+import doctest
+from pkg_resources import resource_listdir
+from zope.testing import cleanup, renormalizing
+import zope.component.eventtesting
+
+def setUpZope(test):
+ zope.component.eventtesting.setUp(test)
+
+def cleanUpZope(test):
+ cleanup.cleanUp()
+
+checker = renormalizing.RENormalizing([
+ # str(Exception) has changed from Python 2.4 to 2.5 (due to
+ # Exception now being a new-style class). This changes the way
+ # exceptions appear in traceback printouts.
+ (re.compile(r"ConfigurationExecutionError: <class '([\w.]+)'>:"),
+ r'ConfigurationExecutionError: \1:'),
+ ])
+
+def suiteFromPackage(name):
+ files = resource_listdir(__name__, name)
+ suite = unittest.TestSuite()
+ for filename in files:
+ if not filename.endswith('.py'):
+ continue
+ if filename.endswith('_fixture.py'):
+ continue
+ if filename == '__init__.py':
+ continue
+
+ dottedname = 'grokcore.component.tests.%s.%s' % (name, filename[:-3])
+ try:
+ test = doctest.DocTestSuite(dottedname,
+ setUp=setUpZope,
+ tearDown=cleanUpZope,
+ checker=checker,
+ optionflags=doctest.ELLIPSIS+
+ doctest.NORMALIZE_WHITESPACE)
+ except ImportError: # or should this accept anything?
+ traceback.print_exc()
+ raise
+ suite.addTest(test)
+ return suite
+
+def test_suite():
+ suite = unittest.TestSuite()
+ for name in ['adapter', 'directive', 'grokker', 'utility', 'view',
+ 'event', 'inherit', 'order', 'subscriptions']:
+ suite.addTest(suiteFromPackage(name))
+
+ api = doctest.DocFileSuite('api.txt')
+ suite.addTest(api)
+
+ # this test cannot follow the normal testing pattern, as the
+ # bug it tests for is only exposed in the context of a doctest
+ grok_component = doctest.DocFileSuite('grok_component.txt',
+ setUp=setUpZope,
+ tearDown=cleanUpZope)
+ suite.addTest(grok_component)
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/conflict.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,89 @@
+"""
+Trying to register two utilities for the same interface (and
+potentially under the same name) will generate a configuration
+conflict:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ ConfigurationConflictError: Conflicting configuration actions
+ For: ('utility', <InterfaceClass grokcore.component.tests.utility.conflict.IUtilityInterface>, 'class and module')
+ <BLANKLINE>
+ <BLANKLINE>
+ For: ('utility', <InterfaceClass grokcore.component.tests.utility.conflict.IUtilityInterface>, 'direct class')
+ <BLANKLINE>
+ <BLANKLINE>
+ For: ('utility', <InterfaceClass grokcore.component.tests.utility.conflict.IUtilityInterface>, 'explicit class')
+ <BLANKLINE>
+ <BLANKLINE>
+ For: ('utility', <InterfaceClass grokcore.component.tests.utility.conflict.IUtilityInterface>, 'implicit class')
+ <BLANKLINE>
+ <BLANKLINE>
+ For: ('utility', <InterfaceClass grokcore.component.tests.utility.conflict.IUtilityInterface>, 'mixed class')
+ <BLANKLINE>
+ <BLANKLINE>
+
+"""
+import grokcore.component as grok
+from zope.interface import Interface, classProvides
+
+class IUtilityInterface(Interface):
+ pass
+
+class IAnotherInterface(Interface):
+ pass
+
+
+class Implicit1(grok.GlobalUtility):
+ grok.implements(IUtilityInterface)
+ grok.name('implicit class')
+
+class Implicit2(grok.GlobalUtility):
+ grok.implements(IUtilityInterface)
+ grok.name('implicit class')
+
+
+class Explicit1(grok.GlobalUtility):
+ grok.implements(IUtilityInterface, IAnotherInterface)
+ grok.provides(IUtilityInterface)
+ grok.name('explicit class')
+
+class Explicit2(grok.GlobalUtility):
+ grok.implements(IUtilityInterface, IAnotherInterface)
+ grok.provides(IUtilityInterface)
+ grok.name('explicit class')
+
+
+class Mixed1(grok.GlobalUtility):
+ grok.implements(IUtilityInterface, IAnotherInterface)
+ grok.provides(IUtilityInterface)
+ grok.name('mixed class')
+
+class Mixed2(grok.GlobalUtility):
+ grok.implements(IUtilityInterface)
+ grok.name('mixed class')
+
+
+class Direct1(grok.GlobalUtility):
+ classProvides(IUtilityInterface)
+ grok.name('direct class')
+ grok.direct()
+
+class Direct2(grok.GlobalUtility):
+ classProvides(IUtilityInterface)
+ grok.name('direct class')
+ grok.direct()
+
+
+class ClassLevel(grok.GlobalUtility):
+ """This utility inherits from Grok's base class and is registered
+ this way."""
+ grok.implements(IUtilityInterface)
+ grok.name('class and module')
+
+class ModuleLevel(object):
+ """This utility doesn't inherit from Grok's base class and is
+ registered explicitly using the module-level directive below."""
+ grok.implements(IUtilityInterface)
+
+grok.global_utility(ModuleLevel, name='class and module')
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,21 @@
+"""
+Subclasses of grok.GlobalUtility that implement more than one interface must
+specify which interface to use for the registration:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.utility.implementsmany.Club'> is implementing
+ more than one interface (use grok.provides to specify which one to use).
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+ pass
+
+class ISpikyClub(interface.Interface):
+ pass
+
+class Club(grok.GlobalUtility):
+ grok.implements(IClub, ISpikyClub)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsmany2.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+"""
+Subclasses of grok.GlobalUtility that implement more than one interface must
+specify which interface to use for the registration:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.utility.implementsmany2.Club'> is implementing
+ more than one interface (use grok.provides to specify which one to use).
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+ pass
+
+class ISpikyClub(interface.Interface):
+ pass
+
+class Club(object):
+ grok.implements(IClub, ISpikyClub)
+
+grok.global_utility(Club)
+
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,13 @@
+"""
+Subclasses of grok.GlobalUtility must implement exactly one interface:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.utility.implementsnone.Club'> must
+ implement at least one interface (use grok.implements to specify).
+"""
+import grokcore.component as grok
+
+class Club(grok.GlobalUtility):
+ pass
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/implementsnone2.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+"""
+Subclasses of grok.GlobalUtility must implement exactly one interface:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.utility.implementsnone2.Club'> must
+ implement at least one interface (use grok.implements to specify).
+"""
+import grokcore.component as grok
+
+class Club(object):
+ pass
+
+grok.global_utility(Club)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+"""
+Subclasses of grok.GlobalUtility that are supposed to be registered
+directly as utilities and which provide more than one interface must
+specify which interface to use for the registration:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.utility.providesmany.Club'>
+ provides more than one interface (use grok.provides to specify which one
+ to use).
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+ pass
+
+class ISpikyClub(interface.Interface):
+ pass
+
+class Club(grok.GlobalUtility):
+ interface.classProvides(IClub, ISpikyClub)
+ grok.direct()
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesmany2.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,25 @@
+"""
+Subclasses of grok.GlobalUtility that are supposed to be registered
+directly as utilities and which provide more than one interface must
+specify which interface to use for the registration:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.utility.providesmany2.Club'>
+ provides more than one interface (use grok.provides to specify which one
+ to use).
+"""
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+ pass
+
+class ISpikyClub(interface.Interface):
+ pass
+
+class Club(object):
+ interface.classProvides(IClub, ISpikyClub)
+
+grok.global_utility(Club, direct=True)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+Subclasses of grok.GlobalUtility must implement exactly one interface:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.utility.providesnone.Club'>
+ must provide at least one interface (use zope.interface.classProvides
+ to specify).
+"""
+import grokcore.component as grok
+
+class Club(grok.GlobalUtility):
+ grok.direct()
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/providesnone2.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,16 @@
+"""
+Subclasses of grok.GlobalUtility must implement exactly one interface:
+
+ >>> grok.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.component.tests.utility.providesnone2.Club'>
+ must provide at least one interface (use zope.interface.classProvides
+ to specify).
+"""
+import grokcore.component as grok
+
+class Club(object):
+ pass
+
+grok.global_utility(Club, direct=True)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/utility/utility.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,199 @@
+"""
+Global utilities can be created by subclassing grok.GlobalUtility:
+
+ >>> grok.testing.grok(__name__)
+ >>> from zope import component
+
+ >>> normal_club = component.getUtility(IClub)
+ >>> IClub.providedBy(normal_club)
+ True
+ >>> isinstance(normal_club, NormalClub)
+ True
+
+Named utilities are registered using grok.name:
+
+ >>> huge_club = component.getUtility(IClub, name='huge')
+ >>> IClub.providedBy(huge_club)
+ True
+ >>> isinstance(huge_club, HugeClub)
+ True
+
+A utility can explicitly specify which interface it should be looked up with.
+
+ >>> spiky_club = component.getUtility(IClub, name='spiky')
+ >>> isinstance(spiky_club, SpikyClub)
+ True
+
+ >>> component.getUtility(ISpikyClub, name='spiky')
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.component.tests.utility.utility.ISpikyClub>,
+ 'spiky')
+
+If a utility implements more than one interface, it has to specify the one to
+use with 'grok.provides':
+
+ >>> nightclub = component.getUtility(INightClub)
+ >>> INightClub.providedBy(nightclub)
+ True
+ >>> isinstance(nightclub, NightClub)
+ True
+
+You can make the class the utility by providing the grok.direct() directive,
+if you also use interface.classProvides instead of grok.provides.
+This is useful for utilities that do nothing but create instances:
+
+ >>> clubmaker = component.getUtility(IClubMaker, 'maker')
+ >>> IClubMaker.providedBy(clubmaker)
+ True
+ >>> clubmaker is ClubMaker
+ True
+
+Utilities (including classes that do not subclass from grok.GlobalUtility) can
+be (re-)registered using grok.global_utility:
+
+ >>> fireplace = component.getUtility(IFireplace)
+ >>> IFireplace.providedBy(fireplace)
+ True
+ >>> isinstance(fireplace, Fireplace)
+ True
+
+ >>> fireplace = component.getUtility(IFireplace, name='hot')
+ >>> IFireplace.providedBy(fireplace)
+ True
+ >>> isinstance(fireplace, Fireplace)
+ True
+
+ >>> home = component.getUtility(IHome)
+ >>> IHome.providedBy(home)
+ True
+ >>> isinstance(home, Home)
+ True
+
+ >>> night = component.getUtility(INightClub, name='cool')
+ >>> IClub.providedBy(night)
+ True
+ >>> isinstance(night, NightClub)
+ True
+
+ >>> spiky = component.getUtility(ISpikyClub)
+ >>> ISpikyClub.providedBy(spiky)
+ True
+ >>> isinstance(spiky, NightClub)
+ True
+
+When re-registering a grok.GlobalUtility, the directives grok.name and
+grok.provides on the class will be used, but can be overriden in the
+grok.global_utility directive:
+
+ >>> small = component.getUtility(ISmallClub, name='tiny')
+ >>> ISmallClub.providedBy(small)
+ True
+ >>> isinstance(small, SmallClub)
+ True
+
+ >>> small2 = component.getUtility(ITinyClub, name='tiny')
+ >>> ISmallClub.providedBy(small2)
+ True
+ >>> isinstance(small2, SmallClub)
+ True
+ >>> small is not small2
+ True
+
+ >>> small3 = component.getUtility(ISmallClub, name='small')
+ >>> ISmallClub.providedBy(small3)
+ True
+ >>> isinstance(small3, SmallClub)
+ True
+ >>> small3 is not small2 and small3 is not small
+ True
+
+Normally one registers a utility factory, such as the class, as a
+global utility. It is also possible to register an arbitrary object directly
+as a global utility. You do this by passing a 'direct' argument set to
+'True'. This can be useful if one needs to register functions (such
+as factory functions) that can be looked up as a utility, or if the
+class you want to register as a global utility has an __init__ that
+takes arguments, where you want to do the instantiation yourself.
+Let's look up an instance we registered this way:
+
+ >>> small4 = component.getUtility(ISmallClub, name='smallish')
+ >>> ISmallClub.providedBy(small4)
+ True
+ >>> isinstance(small4, SmallClub)
+ True
+
+"""
+
+import grokcore.component as grok
+from zope import interface
+
+class IClub(interface.Interface):
+ pass
+
+class ISpikyClub(IClub):
+ pass
+
+class ISmallClub(IClub):
+ pass
+
+class ITinyClub(IClub):
+ pass
+
+class INightClub(interface.Interface):
+ pass
+
+class IClubMaker(interface.Interface):
+ pass
+
+class NormalClub(grok.GlobalUtility):
+ grok.implements(IClub)
+
+class HugeClub(grok.GlobalUtility):
+ grok.implements(IClub)
+ grok.name('huge')
+
+class SpikyClub(grok.GlobalUtility):
+ grok.implements(ISpikyClub)
+ grok.provides(IClub)
+ grok.name('spiky')
+
+class NightClub(grok.GlobalUtility):
+ grok.implements(INightClub, ISpikyClub)
+ grok.provides(INightClub)
+
+class SmallClub(grok.GlobalUtility):
+ grok.implements(ISmallClub, ITinyClub)
+ grok.provides(ISmallClub)
+ grok.name('tiny')
+
+class ClubMaker(grok.GlobalUtility):
+ grok.implements(IClub)
+ interface.classProvides(IClubMaker)
+ grok.direct()
+ grok.name('maker')
+
+class IFireplace(interface.Interface):
+ pass
+
+class IHome(interface.Interface):
+ pass
+
+class Fireplace(object):
+ grok.implements(IFireplace)
+
+class Home(object):
+ grok.implements(IFireplace, IHome)
+
+grok.global_utility(Fireplace)
+grok.global_utility(Fireplace, name='hot')
+grok.global_utility(Home, provides=IHome)
+
+grok.global_utility(NightClub, name='cool')
+grok.global_utility(NightClub, provides=ISpikyClub)
+
+grok.global_utility(SmallClub, provides=ITinyClub)
+grok.global_utility(SmallClub, name='small')
+
+grok.global_utility(SmallClub(), name='smallish',
+ direct=True)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+"""
+You can't call grok.name on a module:
+
+ >>> import grokcore.component.tests.view.nomodulename_fixture
+ Traceback (most recent call last):
+ ...
+ GrokImportError: The 'name' directive can only be used on class level.
+
+"""
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/tests/view/nomodulename_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,5 @@
+"""
+This should fail:
+"""
+import grokcore.component as grok
+grok.name('viewname')
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/util.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/util.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/util.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,143 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok utility functions.
+"""
+import types
+import zope.component.hooks
+from zope.interface.interfaces import IInterface
+from zope.interface import alsoProvides
+from grokcore.component import directive
+
+def _sort_key(component):
+ # If components have a grok.order directive, sort by that.
+ explicit_order, implicit_order = directive.order.bind().get(component)
+ return (explicit_order,
+ component.__module__,
+ implicit_order,
+ component.__class__.__name__)
+
+
+def sort_components(components, key=None):
+ """Sort a list of components using the information provided by
+ `grok.order`.
+ """
+ sort_key = _sort_key
+ if key is not None:
+ sort_key = lambda item: _sort_key(key(item))
+ return sorted(components, key=sort_key)
+
+
+def getSiteManager():
+ site = zope.component.hooks.getSite()
+ if site is None:
+ sm = zope.component.getGlobalSiteManager()
+ else:
+ sm = site.getSiteManager()
+ return sm
+
+
+def provideUtility(component, provides=None, name=u''):
+ sm = getSiteManager()
+ sm.registerUtility(component, provides, name, event=False)
+
+
+def provideAdapter(factory, adapts=None, provides=None, name=''):
+ sm = getSiteManager()
+ sm.registerAdapter(factory, adapts, provides, name, event=False)
+
+
+def provideSubscriptionAdapter(factory, adapts=None, provides=None):
+ sm = getSiteManager()
+ sm.registerSubscriptionAdapter(factory, adapts, provides, event=False)
+
+
+def provideHandler(factory, adapts=None):
+ sm = getSiteManager()
+ sm.registerHandler(factory, adapts, event=False)
+
+def provideInterface(id, interface, iface_type=None, info=''):
+ """register Interface with global site manager as utility
+
+ >>> gsm = zope.component.getGlobalSiteManager()
+
+ >>> from zope.interface import Interface
+ >>> from zope.interface.interfaces import IInterface
+ >>> from zope.component.tests import ITestType
+
+ >>> class I(Interface):
+ ... pass
+ >>> IInterface.providedBy(I)
+ True
+ >>> ITestType.providedBy(I)
+ False
+ >>> interfaces = gsm.getUtilitiesFor(ITestType)
+ >>> list(interfaces)
+ []
+
+ # provide first interface type
+ >>> provideInterface('', I, ITestType)
+ >>> ITestType.providedBy(I)
+ True
+ >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
+ >>> [name for (name, iface) in interfaces]
+ [u'zope.component.interface.I']
+ >>> [iface.__name__ for (name, iface) in interfaces]
+ ['I']
+
+ # provide second interface type
+ >>> class IOtherType(IInterface):
+ ... pass
+ >>> provideInterface('', I, IOtherType)
+
+ >>> ITestType.providedBy(I)
+ True
+ >>> IOtherType.providedBy(I)
+ True
+ >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
+ >>> [name for (name, iface) in interfaces]
+ [u'zope.component.interface.I']
+ >>> interfaces = list(gsm.getUtilitiesFor(IOtherType))
+ >>> [name for (name, iface) in interfaces]
+ [u'zope.component.interface.I']
+
+ >>> class I1(Interface):
+ ... pass
+ >>> provideInterface('', I1)
+ >>> IInterface.providedBy(I1)
+ True
+ >>> ITestType.providedBy(I1)
+ False
+ >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
+ >>> [name for (name, iface) in interfaces]
+ [u'zope.component.interface.I']
+ >>> [iface.__name__ for (name, iface) in interfaces]
+ ['I']
+ """
+ if not id:
+ id = "%s.%s" % (interface.__module__, interface.__name__)
+
+ if not IInterface.providedBy(interface):
+ if not isinstance(interface, (type, types.ClassType)):
+ raise TypeError(id, "is not an interface or class")
+ return
+
+ if iface_type is not None:
+ if not iface_type.extends(IInterface):
+ raise TypeError(iface_type, "is not an interface type")
+ alsoProvides(interface, iface_type)
+ else:
+ iface_type = IInterface
+
+ sm = getSiteManager()
+ sm.registerUtility(interface, iface_type, id, info)
Added: grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/zcml.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/zcml.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.component/src/grokcore/component/zcml.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,71 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok ZCML directives."""
+
+from zope.interface import Interface
+from zope.configuration.fields import GlobalObject
+from zope.schema import TextLine
+
+import martian
+
+
+class IGrokDirective(Interface):
+ """Grok a package or module."""
+
+ package = GlobalObject(
+ title=u"Package",
+ description=u"The package or module to be analyzed by grok.",
+ required=False)
+
+ exclude = TextLine(
+ title=u"Exclude",
+ description=u"Name to exclude in the grokking process.",
+ required=False)
+
+
+# add a cleanup hook so that grok will bootstrap itself again whenever
+# the Component Architecture is torn down.
+def resetBootstrap():
+ # we need to make sure that the grokker registry is clean again
+ the_module_grokker.clear()
+
+from zope.testing.cleanup import addCleanUp
+addCleanUp(resetBootstrap)
+
+the_multi_grokker = martian.MetaMultiGrokker()
+the_module_grokker = martian.ModuleGrokker(the_multi_grokker)
+
+
+def skip_tests(name):
+ return name in ['tests', 'ftests', 'testing']
+
+
+def grokDirective(_context, package, exclude=None):
+ if not exclude:
+ exclude = None
+ do_grok(package.__name__, _context, extra_exclude=exclude)
+
+
+def do_grok(dotted_name, config, extra_exclude=None):
+ if extra_exclude is not None:
+
+ def exclude_filter(name):
+ return skip_tests(name) or extra_exclude == name
+
+ else:
+ exclude_filter = skip_tests
+
+ martian.grok_dotted_name(
+ dotted_name, the_module_grokker, exclude_filter=exclude_filter,
+ config=config)
Added: grokcore.registries/trunk/src/grokcore.site/CHANGES.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/CHANGES.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/CHANGES.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,67 @@
+Changes
+=======
+
+1.6 (unreleased)
+----------------
+
+- Moved the directive `site` from Grok to this package.
+
+- Moved the component `Application` and all the related utilities from Grok
+ to this package.
+
+
+1.5 (2011-01-03)
+----------------
+
+- Moved IApplication and getApplication from the Grok package into
+ this one.
+
+
+1.4 (2010-11-01)
+----------------
+
+- Upped versions requirements for martian and grokcore.component.
+
+1.3 (2010-10-18)
+----------------
+
+- Made package comply to repository policy.
+
+- Update functional tests to only use zope.app.appsetup instead
+ of zope.app.testing.
+
+- Update functional tests not to require zope.app.zcmlfiles
+ anymore.
+
+1.2 (2009-12-20)
+----------------
+
+* Migrated imports from zope.app.component to zope.site.
+
+1.1 (2009-09-18)
+----------------
+
+* Updated dependencies (added missing ones and added separate test
+ dependencies).
+
+* A local utility now implements IAttributeAnnotatable.
+
+* Update code documentation from Grok itself.
+
+* Use 1.0b2 versions.cfg in Grok's release info instead of a local
+ copy; a local copy for all grokcore packages is just too hard to
+ maintain.
+
+
+1.0.1 (2009-06-30)
+------------------
+
+* Reupload to pypi with a correct version of Python which doesn't have
+ a distutils bug.
+
+1.0 (2009-06-29)
+----------------
+
+* Created ``grokcore.site`` by factoring local site based components,
+ grokkers and directives out of Grok.
+
Added: grokcore.registries/trunk/src/grokcore.site/COPYRIGHT.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/COPYRIGHT.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/COPYRIGHT.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+Zope Foundation and Contributors
\ No newline at end of file
Added: grokcore.registries/trunk/src/grokcore.site/LICENSE.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/LICENSE.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/LICENSE.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,44 @@
+Zope Public License (ZPL) Version 2.1
+
+A copyright notice accompanies this license document that identifies the
+copyright holders.
+
+This license has been certified as open source. It has also been designated as
+GPL compatible by the Free Software Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions in source code must retain the accompanying copyright
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying copyright
+notice, this list of conditions, and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to endorse or promote
+products derived from this software without prior written permission from the
+copyright holders.
+
+4. The right to distribute this software or to use it for any purpose does not
+give you the right to use Servicemarks (sm) or Trademarks (tm) of the
+copyright
+holders. Use of them is covered by separate agreement with the copyright
+holders.
+
+5. If any files are modified, you must cause the modified files to carry
+prominent notices stating that you changed the files and the date of any
+change.
+
+Disclaimer
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Added: grokcore.registries/trunk/src/grokcore.site/README.txt
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/README.txt (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/README.txt 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,106 @@
+
+This package provides support to write local site and utilities for
+Zope directly in Python (without ZCML).
+
+.. contents::
+
+
+Setting up ``grokcore.site``
+============================
+
+This package is essentially set up like the `grokcore.component`_
+package, please refer to its documentation for details. The only
+additional ZCML line you will need is::
+
+ <include package="grokcore.site" />
+
+Put this somewhere near the top of your root ZCML file but below the
+line where you include ``grokcore.component``'s configuration.
+
+
+Examples
+========
+
+Global utilities are already managed by `grokcore.component`_.
+
+Here a simple example of a local utility::
+
+ from zope.interface import implements, Interface
+ import grokcore.site
+
+ class IKangaroo(Interface):
+
+ def jump():
+ """Make all kangaroos jump somewhere.
+ """
+
+ class KangarooUtility(grokcore.site.LocalUtility):
+ implements(IKangaroo)
+
+ def jump(self):
+ pass
+
+
+Now, we can register our utility to a local site. That will create
+automatically, and register that utility when we create that site::
+
+
+ class Jungle(grokcore.site.Site):
+
+ grokcore.site.local_utility(KangarooUtility, IKangaroo)
+
+
+If you don't add the last line, you will still have your site, but
+nothing to make jump your kangaroo. Then, you will be able to add
+manually by hand after (if you want).
+
+
+API Overview
+============
+
+Base classes
+------------
+
+``Site``
+ Base class for your site.
+
+``LocalUtility``
+ Base class for a ZODB-persitent local utility.
+
+
+Directives
+----------
+
+``local_utility(factory, provides=None, name=u'', setup=None, public=False, name_in_container=None``)
+ Directive used on a site to register a local utility at the
+ creation time:
+
+ ``factory``
+ Would be the component to register (required parameter),
+
+ ``provides``
+ Would be the interface used to query the local utility (required
+ parameter),
+
+ ``name``
+ Would be the name used to query the local utility,
+
+ ``setup``
+ Would be a function taking parameter. If defined it will be
+ called after the utility is created with it as first and unique
+ parameter.
+
+ ``public``
+ If true, the utility will be created in the site container
+ itself, not in the site manager, and public will be able to
+ access it directly.
+
+ ``name_in_container``
+ Would be used as id for the utility in container itwill be
+ created. If not defined it will ask NameChooser to pick a name
+ for it.
+
+In addition, the ``grokcore.site`` package exposes the
+`grokcore.component`_ API.
+
+.. _grokcore.component: http://pypi.python.org/pypi/grokcore.component
Added: grokcore.registries/trunk/src/grokcore.site/bootstrap.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/bootstrap.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/bootstrap.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,258 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+"""
+
+import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
+from optparse import OptionParser
+
+if sys.platform == 'win32':
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ quote = str
+
+# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
+stdout, stderr = subprocess.Popen(
+ [sys.executable, '-Sc',
+ 'try:\n'
+ ' import ConfigParser\n'
+ 'except ImportError:\n'
+ ' print 1\n'
+ 'else:\n'
+ ' print 0\n'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+has_broken_dash_S = bool(int(stdout.strip()))
+
+# In order to be more robust in the face of system Pythons, we want to
+# run without site-packages loaded. This is somewhat tricky, in
+# particular because Python 2.6's distutils imports site, so starting
+# with the -S flag is not sufficient. However, we'll start with that:
+if not has_broken_dash_S and 'site' in sys.modules:
+ # We will restart with python -S.
+ args = sys.argv[:]
+ args[0:0] = [sys.executable, '-S']
+ args = map(quote, args)
+ os.execv(sys.executable, args)
+# Now we are running with -S. We'll get the clean sys.path, import site
+# because distutils will do it later, and then reset the path and clean
+# out any namespace packages from site-packages that might have been
+# loaded by .pth files.
+clean_path = sys.path[:]
+import site
+sys.path[:] = clean_path
+for k, v in sys.modules.items():
+ if (hasattr(v, '__path__') and
+ len(v.__path__)==1 and
+ not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
+ # This is a namespace package. Remove it.
+ sys.modules.pop(k)
+
+is_jython = sys.platform.startswith('java')
+
+setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
+distribute_source = 'http://python-distribute.org/distribute_setup.py'
+
+# parsing arguments
+def normalize_to_url(option, opt_str, value, parser):
+ if value:
+ if '://' not in value: # It doesn't smell like a URL.
+ value = 'file://%s' % (
+ urllib.pathname2url(
+ os.path.abspath(os.path.expanduser(value))),)
+ if opt_str == '--download-base' and not value.endswith('/'):
+ # Download base needs a trailing slash to make the world happy.
+ value += '/'
+ else:
+ value = None
+ name = opt_str[2:].replace('-', '_')
+ setattr(parser.values, name, value)
+
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
+
+Bootstraps a buildout-based project.
+
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", dest="version",
+ help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+ action="store_true", dest="use_distribute", default=False,
+ help="Use Distribute rather than Setuptools.")
+parser.add_option("--setup-source", action="callback", dest="setup_source",
+ callback=normalize_to_url, nargs=1, type="string",
+ help=("Specify a URL or file location for the setup file. "
+ "If you use Setuptools, this will default to " +
+ setuptools_source + "; if you use Distribute, this "
+ "will default to " + distribute_source +"."))
+parser.add_option("--download-base", action="callback", dest="download_base",
+ callback=normalize_to_url, nargs=1, type="string",
+ help=("Specify a URL or directory for downloading "
+ "zc.buildout and either Setuptools or Distribute. "
+ "Defaults to PyPI."))
+parser.add_option("--eggs",
+ help=("Specify a directory for storing eggs. Defaults to "
+ "a temporary directory that is deleted when the "
+ "bootstrap script completes."))
+parser.add_option("-t", "--accept-buildout-test-releases",
+ dest='accept_buildout_test_releases',
+ action="store_true", default=False,
+ help=("Normally, if you do not specify a --version, the "
+ "bootstrap script and buildout gets the newest "
+ "*final* versions of zc.buildout and its recipes and "
+ "extensions for you. If you use this flag, "
+ "bootstrap and buildout will get the newest releases "
+ "even if they are alphas or betas."))
+parser.add_option("-c", None, action="store", dest="config_file",
+ help=("Specify the path to the buildout configuration "
+ "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout's main function
+if options.config_file is not None:
+ args += ['-c', options.config_file]
+
+if options.eggs:
+ eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
+else:
+ eggs_dir = tempfile.mkdtemp()
+
+if options.setup_source is None:
+ if options.use_distribute:
+ options.setup_source = distribute_source
+ else:
+ options.setup_source = setuptools_source
+
+if options.accept_buildout_test_releases:
+ args.append('buildout:accept-buildout-test-releases=true')
+args.append('bootstrap')
+
+try:
+ import pkg_resources
+ import setuptools # A flag. Sometimes pkg_resources is installed alone.
+ if not hasattr(pkg_resources, '_distribute'):
+ raise ImportError
+except ImportError:
+ ez_code = urllib2.urlopen(
+ options.setup_source).read().replace('\r\n', '\n')
+ ez = {}
+ exec ez_code in ez
+ setup_args = dict(to_dir=eggs_dir, download_delay=0)
+ if options.download_base:
+ setup_args['download_base'] = options.download_base
+ if options.use_distribute:
+ setup_args['no_fake'] = True
+ ez['use_setuptools'](**setup_args)
+ reload(sys.modules['pkg_resources'])
+ import pkg_resources
+ # This does not (always?) update the default working set. We will
+ # do it.
+ for path in sys.path:
+ if path not in pkg_resources.working_set.entries:
+ pkg_resources.working_set.add_entry(path)
+
+cmd = [quote(sys.executable),
+ '-c',
+ quote('from setuptools.command.easy_install import main; main()'),
+ '-mqNxd',
+ quote(eggs_dir)]
+
+if not has_broken_dash_S:
+ cmd.insert(1, '-S')
+
+find_links = options.download_base
+if not find_links:
+ find_links = os.environ.get('bootstrap-testing-find-links')
+if find_links:
+ cmd.extend(['-f', quote(find_links)])
+
+if options.use_distribute:
+ setup_requirement = 'distribute'
+else:
+ setup_requirement = 'setuptools'
+ws = pkg_resources.working_set
+setup_requirement_path = ws.find(
+ pkg_resources.Requirement.parse(setup_requirement)).location
+env = dict(
+ os.environ,
+ PYTHONPATH=setup_requirement_path)
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+ # Figure out the most recent final version of zc.buildout.
+ import setuptools.package_index
+ _final_parts = '*final-', '*final'
+ def _final_version(parsed_version):
+ for part in parsed_version:
+ if (part[:1] == '*') and (part not in _final_parts):
+ return False
+ return True
+ index = setuptools.package_index.PackageIndex(
+ search_path=[setup_requirement_path])
+ if find_links:
+ index.add_find_links((find_links,))
+ req = pkg_resources.Requirement.parse(requirement)
+ if index.obtain(req) is not None:
+ best = []
+ bestv = None
+ for dist in index[req.project_name]:
+ distv = dist.parsed_version
+ if _final_version(distv):
+ if bestv is None or distv > bestv:
+ best = [dist]
+ bestv = distv
+ elif distv == bestv:
+ best.append(dist)
+ if best:
+ best.sort()
+ version = best[-1].version
+if version:
+ requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+if is_jython:
+ import subprocess
+ exitcode = subprocess.Popen(cmd, env=env).wait()
+else: # Windows prefers this, apparently; otherwise we would prefer subprocess
+ exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
+if exitcode != 0:
+ sys.stdout.flush()
+ sys.stderr.flush()
+ print ("An error occurred when trying to install zc.buildout. "
+ "Look above this message for any errors that "
+ "were output by easy_install.")
+ sys.exit(exitcode)
+
+ws.add_entry(eggs_dir)
+ws.require(requirement)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+if not options.eggs: # clean up temporary egg directory
+ shutil.rmtree(eggs_dir)
Added: grokcore.registries/trunk/src/grokcore.site/buildout.cfg
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/buildout.cfg (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/buildout.cfg 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,21 @@
+[buildout]
+develop = .
+parts = interpreter test
+extends = http://svn.zope.org/repos/main/groktoolkit/trunk/grok.cfg
+versions = versions
+extensions = buildout.dumppickedversions
+
+[versions]
+grokcore.site =
+
+[interpreter]
+recipe = zc.recipe.egg
+eggs = grokcore.site
+interpreter = python
+
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = grokcore.site
+ grokcore.site[test]
+defaults = ['--tests-pattern', '^f?tests$', '-v']
Added: grokcore.registries/trunk/src/grokcore.site/setup.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/setup.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/setup.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,58 @@
+from setuptools import setup, find_packages
+import os
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+long_description = (
+ read('README.txt')
+ + '\n' +
+ read('CHANGES.txt')
+ )
+
+tests_require = [
+ 'zope.app.appsetup',
+ 'zope.component',
+ 'zope.configuration',
+ 'zope.location',
+ 'zope.testing',
+ 'grokcore.content',
+ ]
+
+setup(
+ name='grokcore.site',
+ version='1.6dev',
+ author='Grok Team',
+ author_email='grok-dev at zope.org',
+ url='http://grok.zope.org',
+ download_url='http://pypi.python.org/pypi/grokcore.site',
+ description='Grok-like configuration for Zope local site and utilities',
+ long_description=long_description,
+ license='ZPL',
+ classifiers=['Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Programming Language :: Python',
+ 'Framework :: Zope3',
+ ],
+
+ packages=find_packages('src'),
+ package_dir={'': 'src'},
+ namespace_packages=['grokcore'],
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=['setuptools',
+ 'ZODB3',
+ 'zope.event',
+ 'grokcore.component >= 2.1',
+ 'martian >= 0.13',
+ 'zope.annotation',
+ 'zope.component',
+ 'zope.container',
+ 'zope.interface',
+ 'zope.lifecycleevent',
+ 'zope.site',
+ ],
+ tests_require=tests_require,
+ extras_require={'test': tests_require},
+)
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ import pkgutil
+ __path__ = pkgutil.extend_path(__path__, __name__)
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+##############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from zope.site.hooks import getSite
+from grokcore.component import *
+from grokcore.site.directive import site, local_utility
+from grokcore.site.components import Site, LocalUtility, Application
+from grokcore.site.util import getApplication
+
+import grokcore.site.testing
+
+from grokcore.site.interfaces import IGrokcoreSiteAPI
+__all__ = list(IGrokcoreSiteAPI)
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/components.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/components.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/components.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,79 @@
+##############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from persistent import Persistent
+from grokcore.component.interfaces import IContext
+from grokcore.site.interfaces import IApplication
+from zope.annotation.interfaces import IAttributeAnnotatable
+from zope.container.contained import Contained
+from zope.interface import implements
+from zope.site.site import SiteManagerContainer
+
+
+class BaseSite(object):
+ """Mixin to grok sites in Grok applications.
+
+ It's used to let different implementation of sites to exists, and
+ still being grokked correctly.
+ """
+
+
+class Site(BaseSite, SiteManagerContainer):
+ """Mixin for creating sites in Grok applications.
+
+ When an application :class:`grok.Model` or :class:`grok.Container`
+ also inherits from :class:`grokcore.site.Site`, then it can
+ additionally support the registration of local Component
+ Architecture entities like :class:`grokcore.site.LocalUtility` and
+ :class:`grok.Indexes` objects; see those classes for more
+ information.
+ """
+
+
+class Application(Site):
+ """Mixin for creating Grok application objects.
+
+ When a :class:`grokcore.content.Container` (or a
+ :class:`grokcore.content.Model`, though most developers
+ use containers) also inherits from :class:`grokcore.site.Application`,
+ it not only gains the component registration abilities of a
+ :class:`grokcore.site.site`, but will also be listed in the
+ Grok admin control panel as one of the applications
+ that the admin can install directly at the root of their Zope
+ database.
+ """
+ implements(IApplication)
+
+
+class LocalUtility(Contained, Persistent):
+ """The base class for local utilities in Grok applications.
+
+ Defines a utility that will be registered local to a :class:`Site`
+ or :class:`grok.Application`.
+
+ Although application developers can create local utilies without
+ actually subclassing :class:`LocalUtility`, they gain three
+ benefits from doing so. First, their code is more readable
+ because their classes "look like" local utilities to casual
+ readers. Second, their utility will know how to persist itself to
+ the Zope database, which means that they can set its object
+ attributes and know that the values are getting automatically
+ saved. Third, they can omit the `grok.provides()` directive
+ naming the interface that the utility provides, if their class
+ only `grok.implements()` a single interface (unless the interface
+ is one that the `grok.LocalUtility` already implements, in which
+ case Grok cannot tell them apart, and `grok.provides()` must be
+ used explicitly anyway).
+ """
+ implements(IContext, IAttributeAnnotatable)
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/configure.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/configure.zcml (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/configure.zcml 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,13 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:grok="http://namespaces.zope.org/grok">
+
+ <include package="." file="meta.zcml" />
+ <include package="zope.component" file="meta.zcml" />
+ <include package="zope.component" />
+
+ <grok:grok package=".subscriber" />
+ <utility component=".meta.setupUtility" />
+
+</configure>
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/directive.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/directive.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/directive.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,151 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok directives.
+"""
+
+import grokcore.component
+
+from grokcore.site.components import LocalUtility
+
+from zope import interface
+from zope.interface.interfaces import IInterface
+
+import martian
+from martian import util
+from martian.error import GrokImportError
+
+
+class site(martian.Directive):
+ """This directive is used to indicate the Grok site
+ object for which the component should be used/registered.
+ """
+ scope = martian.CLASS
+ store = martian.ONCE
+ validate = martian.validateInterfaceOrClass
+
+
+class local_utility(martian.Directive):
+ """The `grokcore.site.local_utility()` directive.
+
+ Place this directive inside of a `grokcore.site.Site` subclass,
+ and provide the name of a utility you want activated inside of
+ that site::
+
+ class MySite(grokcore.site.Site):
+ grok.local_utility(MyMammothUtility)
+ ...
+
+ This directive can be supplied several times within the same site.
+ Thanks to the presence of this directive, any time an instance of
+ your class is created in the Zope database it will have a copy of
+ the given local utility installed along with it.
+
+ This directive accepts several normal Component-registration keyword
+ arguments, like `provides` and `name`, and uses them each time it
+ registers your local utility.
+
+ If you do not supply a `provides` keyword, then Grok attempts to
+ guess a sensible default. Its first choice is to use any
+ interface(s) that you listed with the grok.provides() directive
+ when defining your utility. Otherwise, if your utility is a
+ subclass of `grokcore.site.LocalUtility`, then Grok will use any
+ interfaces that your utility supplies beyond those are supplied
+ because of its inheritance from `grokcore.site.LocalUtility`.
+ Else, as a final fallback, it checks to see whether the class you
+ are registering supplies one, and only one, interface; if so, then
+ it can register the utility unambiguously as providing that one
+ interface.
+
+ """
+
+ scope = martian.CLASS
+ store = martian.DICT
+
+ def factory(self, factory, provides=None, name=u'',
+ setup=None, public=False, name_in_container=None):
+ if provides is not None and not IInterface.providedBy(provides):
+ raise GrokImportError("You can only pass an interface to the "
+ "provides argument of %s." % self.name)
+
+ if provides is None:
+ # We cannot bind the provides directive and get information
+ # from the factory, so we do it "manually" as we know how
+ # to get to the information.
+ dotted = grokcore.component.provides.dotted_name()
+ provides = getattr(factory, dotted, None)
+
+ if provides is None:
+ if util.check_subclass(factory, LocalUtility):
+ baseInterfaces = interface.implementedBy(LocalUtility)
+ utilityInterfaces = interface.implementedBy(factory)
+ provides = list(utilityInterfaces - baseInterfaces)
+
+ if len(provides) == 0 and len(list(utilityInterfaces)) > 0:
+ raise GrokImportError(
+ "Cannot determine which interface to use "
+ "for utility registration of %r. "
+ "It implements an interface that is a specialization "
+ "of an interface implemented by grok.LocalUtility. "
+ "Specify the interface by either using grok.provides "
+ "on the utility or passing 'provides' to "
+ "grok.local_utility." % factory, factory)
+ else:
+ provides = list(interface.implementedBy(factory))
+
+ util.check_implements_one_from_list(provides, factory)
+ provides = provides[0]
+
+ if (provides, name) in self.frame.f_locals.get(self.dotted_name(), {}):
+ raise GrokImportError(
+ "Conflicting local utility registration %r. "
+ "Local utilities are registered multiple "
+ "times for interface %r and name %r." %
+ (factory, provides, name), factory)
+
+ info = LocalUtilityInfo(factory, provides, name, setup, public,
+ name_in_container)
+ return (provides, name), info
+
+
+class LocalUtilityInfo(object):
+ """The information about how to register a local utility.
+
+ An instance of this class is created for each
+ `grokcore.site.local_utility()` in a Grok application's code, to
+ remember how the user wants their local utility registered.
+ Later, whenever the application creates new instances of the site
+ or application for which the local utility directive was supplied,
+ this block of information is used as the parameters to the
+ creation of the local utility which is created along with the new
+ site in the Zope database.
+
+ """
+ _order = 0
+
+ def __init__(self, factory, provides, name=u'',
+ setup=None, public=False, name_in_container=None):
+ self.factory = factory
+ self.provides = provides
+ self.name = name
+ self.setup = setup
+ self.public = public
+ self.name_in_container = name_in_container
+
+ self.order = LocalUtilityInfo._order
+ LocalUtilityInfo._order += 1
+
+ def __cmp__(self, other):
+ # LocalUtilityInfos have an inherit sort order by which the
+ # registrations take place.
+ return cmp(self.order, other.order)
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftesting.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftesting.zcml (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftesting.zcml 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:grok="http://namespaces.zope.org/grok"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="grokcore.site"
+ package="grokcore.site">
+
+ <include package="zope.app.appsetup" file="ftesting.zcml" />
+
+ <include package="grokcore.site" file="meta.zcml" />
+ <include package="grokcore.site" />
+
+ <grok:grok package="grokcore.site.ftests" />
+
+</configure>
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/application.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/application.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/application/application.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,52 @@
+"""
+An application is a mixin for grok application objects.
+
+You can get the current application by using the
+grok.getApplication() function. Typically this will return the same
+object as grok.getSite(), but it is possible to have sub-Site objects
+which will be returned for grok.getSite(), where-as grok.getApplication
+will walk up the tree until it reaches the top-level site object.
+
+Let's create an application, then get it using grok.getApplication():
+
+ >>> import grokcore.site
+ >>> import zope.site.hooks
+ >>> root = getRootFolder()
+ >>> app = grokcore.site.util.create_application(Cave, root, 'mycave')
+ >>> root['cave'] = app
+ >>> zope.site.hooks.setSite(app)
+ >>> grokcore.site.getApplication()
+ <grokcore.site.ftests.application.application.Cave object at ...>
+
+Or get it using getSite():
+
+ >>> from zope.component.hooks import getSite
+ >>> getSite()
+ <grokcore.site.ftests.application.application.Cave object at ...>
+
+Now we can create a container with a sub-site. When we call grok.getSite()
+we'll get the box:
+
+ >>> root['cave']['box'] = WoodBox()
+ >>> zope.site.hooks.setSite(root['cave']['box'])
+ >>> getSite()
+ <grokcore.site.ftests.application.application.WoodBox object at ...>
+
+But when we call grokcore.site.util.getApplication() we get the cave:
+
+ >>> grokcore.site.getApplication()
+ <grokcore.site.ftests.application.application.Cave object at ...>
+
+"""
+import grokcore.content
+import grokcore.site
+
+
+class Cave(grokcore.content.Container, grokcore.site.Application):
+ """A shelter for homeless cavemen.
+ """
+
+
+class WoodBox(grokcore.content.Container, grokcore.site.Site):
+ """A prehistoric container for holding ZCA registries.
+ """
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/site.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/site.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/site/site.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,51 @@
+"""
+A site can be created by mixing in grok.Site into a grok.Model or
+grok.Container.
+
+ >>> from zope import interface
+ >>> from zope.location.interfaces import IPossibleSite, ISite
+ >>> manfred = Mammoth()
+ >>> IPossibleSite.providedBy(manfred)
+ True
+ >>> herd = Herd()
+ >>> IPossibleSite.providedBy(herd)
+ True
+ >>> nonsite = NonSite()
+ >>> IPossibleSite.providedBy(nonsite)
+ False
+ >>> nonsitecontainer = NonSiteContainer()
+ >>> IPossibleSite.providedBy(nonsitecontainer)
+ False
+
+While manfred and herd are possible sites, they are not yet sites;
+
+ >>> ISite.providedBy(manfred)
+ False
+ >>> ISite.providedBy(herd)
+ False
+
+When a site is added to a container it will be initialized as a site
+(when the ObjectAddedEvent is fired):
+
+ >>> nonsitecontainer['manfred'] = manfred
+ >>> ISite.providedBy(manfred)
+ True
+ >>> nonsitecontainer['herd'] = herd
+ >>> ISite.providedBy(herd)
+ True
+"""
+import grokcore.site
+from persistent import Persistent
+from zope.container.btree import BTreeContainer
+
+class Mammoth(grokcore.site.Site):
+ pass
+
+class Herd(grokcore.site.Site):
+ pass
+
+class NonSite(Persistent):
+ pass
+
+class NonSiteContainer(BTreeContainer):
+ pass
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/test_grok_functional.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/test_grok_functional.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/test_grok_functional.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,40 @@
+import unittest
+import grokcore.site
+
+from pkg_resources import resource_listdir
+from zope.testing import doctest
+from zope.app.appsetup.testlayer import ZODBLayer
+
+FunctionalLayer = ZODBLayer(grokcore.site)
+
+
+def suiteFromPackage(name):
+ files = resource_listdir(__name__, name)
+ suite = unittest.TestSuite()
+ for filename in files:
+ if not filename.endswith('.py'):
+ continue
+ if filename == '__init__.py':
+ continue
+
+ dottedname = 'grokcore.site.ftests.%s.%s' % (name, filename[:-3])
+ test = doctest.DocTestSuite(
+ dottedname,
+ extraglobs=dict(getRootFolder=FunctionalLayer.getRootFolder),
+ optionflags=(doctest.ELLIPSIS+
+ doctest.NORMALIZE_WHITESPACE+
+ doctest.REPORT_NDIFF)
+ )
+ test.layer = FunctionalLayer
+
+ suite.addTest(test)
+ return suite
+
+def test_suite():
+ suite = unittest.TestSuite()
+ for name in ['utility', 'site', 'application']:
+ suite.addTest(suiteFromPackage(name))
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,141 @@
+"""
+Local Utilities can be registered on subclasses of grok.Site using
+grok.local_utility:
+
+ >>> cave = Cave()
+ >>> getRootFolder()["cave"] = cave
+
+ >>> from zope import component
+ >>> from zope.site.hooks import getSite, setSite
+ >>> setSite(cave)
+
+ >>> fireplace = component.getUtility(IFireplace)
+ >>> IFireplace.providedBy(fireplace)
+ True
+ >>> isinstance(fireplace, Fireplace)
+ True
+
+ >>> club = component.getUtility(IClub)
+ >>> IClub.providedBy(club)
+ True
+ >>> isinstance(club, Club)
+ True
+
+ >>> spiky = component.getUtility(IClub, name='spiky')
+ >>> IClub.providedBy(spiky)
+ True
+ >>> isinstance(spiky, SpikyClub)
+ True
+
+ >>> mammoth = component.getUtility(IMammoth)
+ >>> IMammoth.providedBy(mammoth)
+ True
+ >>> isinstance(mammoth, Mammoth)
+ True
+
+ >>> tiger = component.getUtility(IMammoth, name='tiger')
+ >>> IMammoth.providedBy(tiger)
+ True
+ >>> isinstance(tiger, SabretoothTiger)
+ True
+
+ >>> painting = component.getUtility(IPainting, name='blackandwhite')
+ >>> IPainting.providedBy(painting)
+ True
+ >>> isinstance(painting, CavePainting)
+ True
+
+ >>> colored = component.getUtility(IPainting, name='color')
+ >>> IPainting.providedBy(colored)
+ True
+ >>> isinstance(colored, ColoredCavePainting)
+ True
+
+Since it is a local utility, it is not available outside its site:
+
+ >>> setSite(None)
+ >>> component.getUtility(IFireplace)
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IFireplace>, '')
+
+ >>> component.getUtility(IClub)
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IClub>, '')
+
+ >>> component.getUtility(IClub, name='spiky')
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IClub>, 'spiky')
+
+ >>> component.getUtility(IMammoth)
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IMammoth>, '')
+
+ >>> component.getUtility(IMammoth, name='tiger')
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IMammoth>, 'tiger')
+
+ >>> component.getUtility(IPainting, name='blackandwhite')
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IPainting>, 'blackandwhite')
+
+ >>> component.getUtility(IPainting, name='color')
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.local.IPainting>, 'color')
+"""
+import grokcore.site
+from zope import interface
+import persistent
+
+class IFireplace(interface.Interface):
+ pass
+
+class IClub(interface.Interface):
+ pass
+
+class ISpiky(interface.Interface):
+ pass
+
+class IMammoth(interface.Interface):
+ pass
+
+class Fireplace(grokcore.site.LocalUtility):
+ interface.implements(IFireplace)
+
+class Club(object):
+ interface.implements(IClub)
+
+class SpikyClub(object):
+ interface.implements(IClub, ISpiky)
+
+class Mammoth(grokcore.site.LocalUtility):
+ interface.implements(IMammoth, IClub)
+
+class SabretoothTiger(grokcore.site.LocalUtility):
+ interface.implements(IMammoth, IClub)
+ grokcore.site.provides(IMammoth)
+
+class IPainting(persistent.interfaces.IPersistent):
+ pass
+
+class CavePainting(grokcore.site.LocalUtility):
+ interface.implements(IPainting)
+
+class ColoredCavePainting(grokcore.site.LocalUtility):
+ interface.implements(IPainting)
+ grokcore.site.provides(IPainting)
+
+class Cave(grokcore.site.Site):
+ grokcore.site.local_utility(Fireplace)
+ grokcore.site.local_utility(Club)
+ grokcore.site.local_utility(SpikyClub, provides=IClub, name='spiky')
+ grokcore.site.local_utility(Mammoth, provides=IMammoth)
+ grokcore.site.local_utility(SabretoothTiger, name='tiger')
+ grokcore.site.local_utility(CavePainting, name='blackandwhite', provides=IPainting)
+ grokcore.site.local_utility(ColoredCavePainting, name='color')
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local_override.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local_override.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/local_override.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,38 @@
+"""
+Local Utilities can be registered on subclasses of grok.Site using
+grok.local_utility:
+
+ >>> cave = SpikyCave()
+ >>> getRootFolder()['cave'] = cave
+
+ >>> from zope import component
+ >>> from zope.site.hooks import getSite, setSite
+ >>> setSite(cave)
+
+ >>> club = component.getUtility(IClub)
+ >>> IClub.providedBy(club)
+ True
+ >>> isinstance(club, SpikyClub)
+ True
+
+ >>> list(cave.getSiteManager().keys())
+ [u'SpikyClub']
+"""
+import grokcore.site
+from zope import interface
+
+class IClub(interface.Interface):
+ pass
+
+class Club(grokcore.site.LocalUtility):
+ interface.implements(IClub)
+
+class SpikyClub(grokcore.site.LocalUtility):
+ interface.implements(IClub)
+
+class Cave(grokcore.site.Site):
+ grokcore.site.local_utility(Club)
+
+class SpikyCave(Cave):
+ grokcore.site.local_utility(SpikyClub)
+
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/public.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/public.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/public.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,44 @@
+"""
+By default, a utility is not in the public site; it's in ++etc++site. We can
+also specify the utility to be public. It will then be created in the container
+that is the site. The name the utility should have in the container can
+be controlled using name_in_container:
+
+ >>> cave = Cave()
+ >>> getRootFolder()["cave"] = cave
+
+ >>> from zope import component
+ >>> from zope.site.hooks import getSite, setSite
+ >>> setSite(cave)
+ >>> cave['fireplace'] is component.getUtility(IFireplace)
+ True
+
+name_in_container can also be used for objects stored under the site manager
+(that is in ++etc++site):
+
+ >>> cave2 = Cave2()
+ >>> getRootFolder()['cave2'] = cave2
+ >>> setSite(cave2)
+ >>> (cave2.getSiteManager()['fireplace'] is
+ ... component.getUtility(IFireplace))
+ True
+
+"""
+
+import grokcore.site
+from zope import interface
+from zope.container.btree import BTreeContainer
+
+class IFireplace(interface.Interface):
+ pass
+
+class Fireplace(grokcore.site.LocalUtility):
+ interface.implements(IFireplace)
+
+class Cave(BTreeContainer, grokcore.site.Site):
+ grokcore.site.local_utility(Fireplace, public=True,
+ name_in_container='fireplace')
+
+class Cave2(BTreeContainer, grokcore.site.Site):
+ grokcore.site.local_utility(Fireplace, public=False,
+ name_in_container='fireplace')
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/subclass.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/subclass.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/ftests/utility/subclass.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,101 @@
+"""
+Subclassed sites inherit all local utilities of their base classes:
+
+ >>> cave = BigCave()
+ >>> getRootFolder()["cave"] = cave
+
+ >>> from zope import component
+ >>> from zope.site.hooks import getSite, setSite
+
+ >>> setSite(cave)
+ >>> fireplace = component.getUtility(IFireplace)
+ >>> IFireplace.providedBy(fireplace)
+ True
+ >>> isinstance(fireplace, Fireplace)
+ True
+
+Additional utilities can be registered in the subclass:
+
+ >>> hollow = HollowCave()
+ >>> getRootFolder()["hollow"] = hollow
+
+ >>> setSite(hollow)
+ >>> fireplace = component.getUtility(IFireplace)
+ >>> IFireplace.providedBy(fireplace)
+ True
+ >>> isinstance(fireplace, Fireplace)
+ True
+
+ >>> painting = component.getUtility(IPainting)
+ >>> IPainting.providedBy(painting)
+ True
+ >>> isinstance(painting, Painting)
+ True
+
+Those do not influence the base class:
+
+ >>> setSite(cave)
+ >>> painting = component.getUtility(IPainting)
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: (<InterfaceClass grokcore.site.ftests.utility.subclass.IPainting>, '')
+
+This works various levels of inheritance deep:
+
+ >>> very_hollow = VeryHollowCave()
+ >>> getRootFolder()['very_hollow'] = very_hollow
+
+ >>> setSite(very_hollow)
+ >>> fireplace = component.getUtility(IFireplace)
+ >>> painting = component.getUtility(IPainting)
+ >>> great_painting = component.getUtility(IPainting, 'great')
+ >>> bad_painting = component.getUtility(IPainting, 'bad')
+
+And with inheritance hierarchies where a base class is inherited multiple
+times through different routes:
+
+ >>> scary = ScaryCave()
+ >>> getRootFolder()['scary'] = scary
+
+ >>> setSite(scary)
+ >>> fireplace = component.getUtility(IFireplace)
+ >>> painting = component.getUtility(IPainting)
+ >>> great_painting = component.getUtility(IPainting, 'great')
+ >>> bad_painting = component.getUtility(IPainting, 'bad')
+
+"""
+import grokcore.site
+from zope import interface
+
+class IFireplace(interface.Interface):
+ pass
+
+class IPainting(interface.Interface):
+ pass
+
+class Fireplace(grokcore.site.LocalUtility):
+ interface.implements(IFireplace)
+
+class Painting(grokcore.site.LocalUtility):
+ interface.implements(IPainting)
+
+class Cave(grokcore.site.Site):
+ # we use name_in_container here to prevent multiple registrations
+ # since storing the utilities multiple times under the same name
+ # would raise a DuplicationError
+ grokcore.site.local_utility(Fireplace, name_in_container='fireplace')
+
+class BigCave(Cave):
+ pass
+
+class HollowCave(Cave):
+ grokcore.site.local_utility(Painting)
+
+class VeryHollowCave(HollowCave):
+ grokcore.site.local_utility(Painting, name='great')
+ grokcore.site.local_utility(Painting, name='bad')
+
+# this cave subclasses from Cave twice
+class ScaryCave(VeryHollowCave, Cave):
+ pass
+
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/interfaces.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/interfaces.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/interfaces.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,93 @@
+##############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from zope.interface import Interface, Attribute, implements
+from zope.component.interfaces import IObjectEvent
+from grokcore.component.interfaces import IGrokcoreComponentAPI
+
+
+class IApplication(Interface):
+ """Interface to mark the local site used as application root.
+ """
+
+
+class IApplicationInitializedEvent(IObjectEvent):
+ """A Grok Application has been created with success and is now ready
+ to be used.
+
+ This event can be used to trigger the creation of contents or other tasks
+ that require the application to be fully operational : utilities installed
+ and indexes created in the catalog."""
+
+
+class ApplicationInitializedEvent(object):
+ """A Grok Application has been created and is now ready to be used.
+ """
+ implements(IApplicationInitializedEvent)
+
+ def __init__(self, app):
+ assert IApplication.providedBy(app)
+ self.object = app
+
+
+class IUtilityInstaller(Interface):
+ """This install an utility in a site. Let you have different
+ 'installation' method if you want (one for Zope2 / Zope3).
+ """
+
+ def __call__(site, utility, provides, name=u'',
+ name_in_container=None, public=False, setup=None):
+ """Setup an utility.
+ """
+
+
+class IBaseClasses(Interface):
+ Site = Attribute("Mixin class for sites.")
+
+ LocalUtility = Attribute("Base class for local utilities.")
+
+ Application = Attribute("Base class for applications.")
+
+
+class IDirectives(Interface):
+ def local_utility(factory, provides=None, name=u'',
+ setup=None, public=False, name_in_container=None):
+ """Register a local utility.
+
+ factory - the factory that creates the local utility
+ provides - the interface the utility should be looked up with
+ name - the name of the utility
+ setup - a callable that receives the utility as its single argument,
+ it is called after the utility has been created and stored
+ public - if False, the utility will be stored below ++etc++site
+ if True, the utility will be stored directly in the site.
+ The site should in this case be a container.
+ name_in_container - the name to use for storing the utility
+ """
+
+ def provides(interface):
+ """Explicitly specify with which interface a component will be
+ looked up."""
+
+
+class IGrokcoreSiteAPI(IGrokcoreComponentAPI, IBaseClasses, IDirectives):
+ """grokcore.site's public API."""
+
+ IApplication = Attribute('The application model interface')
+
+ def getSite():
+ """Get the current site."""
+
+ def getApplication():
+ """Return the nearest enclosing `grok.Application`."""
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,131 @@
+#############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from zope import component
+
+from zope.lifecycleevent.interfaces import IObjectAddedEvent
+from zope.container.interfaces import IContainer, INameChooser
+
+import martian
+from martian.error import GrokError
+
+import grokcore.component
+import grokcore.site
+import grokcore.site.components
+import grokcore.site.interfaces
+
+
+class SiteGrokker(martian.ClassGrokker):
+ """Grokker for subclasses of `grokcore.site.Site`."""
+ martian.component(grokcore.site.components.BaseSite)
+ martian.priority(500)
+ martian.directive(grokcore.site.local_utility, name='infos')
+
+ def execute(self, factory, config, infos, **kw):
+ if not infos:
+ return False
+
+ infos = infos.values()
+ for info in infos:
+ if info.public and not IContainer.implementedBy(factory):
+ raise GrokError(
+ "Cannot set public to True with grok.local_utility as "
+ "the site (%r) is not a container." %
+ factory, factory)
+
+ # Store the list of info objects in their "natural" order on the
+ # site class. They will be picked up by a subscriber doing the
+ # actual registrations in definition order.
+ factory.__grok_utilities_to_install__ = sorted(infos)
+ adapts = (factory, IObjectAddedEvent)
+
+ config.action(
+ discriminator=None,
+ callable=grokcore.component.provideHandler,
+ args=(localUtilityRegistrationSubscriber, adapts),
+ )
+ return True
+
+
+def localUtilityRegistrationSubscriber(site, event):
+ """A subscriber that fires to set up local utilities.
+ """
+ installed = getattr(site, '__grok_utilities_installed__', False)
+ if installed:
+ return
+
+ setupUtility = component.getUtility(
+ grokcore.site.interfaces.IUtilityInstaller)
+ for info in getattr(site.__class__, '__grok_utilities_to_install__', []):
+ setupUtility(site, info.factory(), info.provides, name=info.name,
+ name_in_container=info.name_in_container,
+ public=info.public, setup=info.setup)
+
+ # we are done. If this subscriber gets fired again, we therefore
+ # do not register utilities anymore
+ site.__grok_utilities_installed__ = True
+
+
+ at grokcore.component.provider(grokcore.site.interfaces.IUtilityInstaller)
+def setupUtility(site, utility, provides, name=u'',
+ name_in_container=None, public=False, setup=None):
+ """Set up a utility in a site.
+
+ site - the site to set up the utility in
+ utility - the utility to set up
+ provides - the interface the utility should be registered with
+ name - the name the utility should be registered under, default
+ the empty string (no name)
+ name_in_container - if given it will be used to add the utility
+ object to its container. Otherwise a name will be made up
+ public - if False, the utility will be stored in the site manager. If
+ True, the utility will be storedin the site (it is assumed the
+ site is a container)
+ setup - if not None, it will be called with the utility as its first
+ argument. This function can then be used to further set up the
+ utility.
+ """
+ site_manager = site.getSiteManager()
+
+ if not public:
+ container = site_manager
+ else:
+ container = site
+
+ if name_in_container is None:
+ name_in_container = INameChooser(container).chooseName(
+ utility.__class__.__name__, utility)
+ container[name_in_container] = utility
+
+ if setup is not None:
+ setup(utility)
+
+ site_manager.registerUtility(utility, provided=provides, name=name)
+
+
+class ApplicationGrokker(martian.ClassGrokker):
+ """Grokker for Grok application classes."""
+ martian.component(grokcore.site.components.Application)
+ martian.priority(500)
+
+ def grok(self, name, factory, module_info, config, **kw):
+ # XXX fail loudly if the same application name is used twice.
+ provides = grokcore.site.interfaces.IApplication
+ name = '%s.%s' % (module_info.dotted_name, name)
+ config.action(
+ discriminator=('utility', provides, name),
+ callable=grokcore.component.provideUtility,
+ args=(factory, provides, name),
+ )
+ return True
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.zcml
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.zcml (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/meta.zcml 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,9 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:meta="http://namespaces.zope.org/meta"
+ xmlns:grok="http://namespaces.zope.org/grok">
+
+ <include package="grokcore.component" file="meta.zcml" />
+ <grok:grok package=".meta" />
+
+</configure>
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/subscriber.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/subscriber.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/subscriber.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,35 @@
+##############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from zope.lifecycleevent.interfaces import IObjectAddedEvent
+from zope.site import LocalSiteManager
+
+import grokcore.component
+from grokcore.site.components import Site
+
+ at grokcore.component.subscribe(Site, IObjectAddedEvent)
+def addSiteHandler(site, event):
+ """Add a local site manager to a Grok site object upon its creation.
+
+ Grok registers this function so that it gets called each time a
+ `grokcore.site.Site` instance is added to a container. It creates
+ a local site manager and installs it on the newly created site.
+
+ """
+ sitemanager = LocalSiteManager(site)
+ # LocalSiteManager creates the 'default' folder in its __init__.
+ # It's not needed anymore in new versions of Zope 3, therefore we
+ # remove it
+ del sitemanager['default']
+ site.setSiteManager(sitemanager)
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/testing.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/testing.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/testing.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+##############################################################################
+#
+# Copyright (c) 2007-2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Grok test helpers
+"""
+from zope.configuration.config import ConfigurationMachine
+from grokcore.component import zcml
+
+def grok(module_name):
+ config = ConfigurationMachine()
+ zcml.do_grok('grokcore.component.meta', config)
+ zcml.do_grok('grokcore.site.meta', config)
+ zcml.do_grok(module_name, config)
+ config.execute_actions()
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# make this directory a package
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/application.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/application.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/application/application.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,37 @@
+"""
+
+After grokking a module that defines an application, the application factory is
+available as a utility::
+
+ >>> from grokcore.site import testing
+ >>> testing.grok(__name__)
+
+ >>> import zope.component
+ >>> import grokcore.site.interfaces
+ >>> calendar_app = zope.component.getUtility(
+ ... grokcore.site.interfaces.IApplication,
+ ... name='grokcore.site.tests.application.application.Calendar')
+
+ >>> calendar_app
+ <class 'grokcore.site.tests.application.application.Calendar'>
+
+Applications are both containers and sites::
+
+ >>> issubclass(calendar_app, grokcore.site.Site)
+ True
+
+Applications can be instanciated without any arguments::
+
+ >>> calendar = calendar_app()
+ >>> calendar
+ <grokcore.site.tests.application.application.Calendar object at 0x...>
+
+"""
+
+import grokcore.site
+
+
+class Calendar(grokcore.site.Application):
+ """A calendar application that knows about ancient
+ calendar systems from the stone age.
+ """
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/test_grok.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/test_grok.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/test_grok.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,50 @@
+import re
+import unittest
+from pkg_resources import resource_listdir
+from zope.testing import doctest, cleanup, renormalizing
+import zope.component.eventtesting
+
+def setUpZope(test):
+ zope.component.eventtesting.setUp(test)
+
+def cleanUpZope(test):
+ cleanup.cleanUp()
+
+checker = renormalizing.RENormalizing([
+ # str(Exception) has changed from Python 2.4 to 2.5 (due to
+ # Exception now being a new-style class). This changes the way
+ # exceptions appear in traceback printouts.
+ (re.compile(r"ConfigurationExecutionError: <class '([\w.]+)'>:"),
+ r'ConfigurationExecutionError: \1:'),
+ ])
+
+def suiteFromPackage(name):
+ files = resource_listdir(__name__, name)
+ suite = unittest.TestSuite()
+ for filename in files:
+ if not filename.endswith('.py'):
+ continue
+ if filename.endswith('_fixture.py'):
+ continue
+ if filename == '__init__.py':
+ continue
+
+ dottedname = 'grokcore.site.tests.%s.%s' % (name, filename[:-3])
+ test = doctest.DocTestSuite(dottedname,
+ setUp=setUpZope,
+ tearDown=cleanUpZope,
+ checker=checker,
+ optionflags=doctest.ELLIPSIS+
+ doctest.NORMALIZE_WHITESPACE)
+
+ suite.addTest(test)
+ return suite
+
+def test_suite():
+ suite = unittest.TestSuite()
+ for name in ['utility', 'application']:
+ suite.addTest(suiteFromPackage(name))
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/__init__.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/__init__.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/__init__.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1 @@
+# this is a package
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+"""
+Anything can be registered as a local utility. If it implements a single
+interface, there is no need to specify which interface it provides.
+
+In this test, the utility implements more than one interface, so it cannot be
+registered as a local utility.
+
+ >>> import grokcore.site.tests.utility.local_implementsmany_fixture
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.site.tests.utility.local_implementsmany_fixture.Fireplace'>
+ is implementing more than one interface (use grok.provides to specify
+ which one to use).
+
+"""
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsmany_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+import grokcore.site
+from zope import interface
+
+class IHome(interface.Interface):
+ pass
+
+class IFireplace(interface.Interface):
+ pass
+
+class Fireplace(object):
+ interface.implements(IHome, IFireplace)
+
+class Cave(grokcore.site.Site):
+ grokcore.site.local_utility(Fireplace)
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+Anything can be registered as a local utility. If it implements a single
+interface, there is no need to specify which interface it provides.
+
+In this test, the utility does not implement any interface, so it cannot be
+registered as a local utility.
+
+ >>> import grokcore.site.tests.utility.local_implementsnone_fixture
+ Traceback (most recent call last):
+ ...
+ GrokError: <class 'grokcore.site.tests.utility.local_implementsnone_fixture.Fireplace'>
+ must implement at least one interface (use grok.implements to specify).
+
+"""
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+ >>> import grokcore.site.tests.utility.local_implementsnone2_fixture
+ Traceback (most recent call last):
+ ...
+ GrokImportError: ("Cannot determine which interface to use for utility
+ registration of
+ <class 'grokcore.site.tests.utility.local_implementsnone2_fixture.Fireplace'>.
+ It implements an interface that is a specialization of an interface
+ implemented by grok.LocalUtility. Specify the interface by either
+ using grok.provides on the utility or passing 'provides' to
+ grok.local_utility.",
+ <class 'grokcore.site.tests.utility.local_implementsnone2_fixture.Fireplace'>)
+
+"""
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone2_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,12 @@
+import grokcore.site
+from zope import interface
+import persistent
+
+class ISpecialPersistent(persistent.interfaces.IPersistent):
+ pass
+
+class Fireplace(grokcore.site.LocalUtility):
+ interface.implements(ISpecialPersistent)
+
+class Cave(grokcore.site.Site):
+ grokcore.site.local_utility(Fireplace)
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/local_implementsnone_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,7 @@
+import grokcore.site
+
+class Fireplace(object):
+ pass
+
+class Cave(grokcore.site.Site):
+ grokcore.site.local_utility(Fireplace)
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+When you try to register multiple classes with the same (interface, name)
+combination multiple times using grok.local_utility, we expect an error:
+
+ >>> import grokcore.site.tests.utility.multiple_class_fixture
+ Traceback (most recent call last):
+ ...
+ GrokImportError: ("Conflicting local utility registration
+ <class 'grokcore.site.tests.utility.multiple_class_fixture.Fireplace2'>.
+ Local utilities are registered multiple times for interface
+ <InterfaceClass grokcore.site.tests.utility.multiple_class_fixture.IFireplace>
+ and name 'Foo'.",
+ <class 'grokcore.site.tests.utility.multiple_class_fixture.Fireplace2'>)
+"""
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_class_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+import grokcore.site
+from zope import interface
+
+class IFireplace(interface.Interface):
+ pass
+
+class Fireplace(grokcore.site.LocalUtility):
+ interface.implements(IFireplace)
+
+class Fireplace2(grokcore.site.LocalUtility):
+ interface.implements(IFireplace)
+
+class Cave(grokcore.site.Site):
+ grokcore.site.local_utility(Fireplace, name='Foo')
+ grokcore.site.local_utility(Fireplace2, name='Foo')
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,14 @@
+"""
+When you call the grok.local_utility directive multiple times specifying
+the same (interface, name) combination, we expect an error:
+
+ >>> import grokcore.site.tests.utility.multiple_directive_fixture
+ Traceback (most recent call last):
+ ...
+ GrokImportError: ("Conflicting local utility registration
+ <class 'grokcore.site.tests.utility.multiple_directive_fixture.Fireplace2'>.
+ Local utilities are registered multiple times for interface
+ <InterfaceClass grokcore.site.tests.utility.multiple_directive_fixture.IFireplace>
+ and name u''.",
+ <class 'grokcore.site.tests.utility.multiple_directive_fixture.Fireplace2'>)
+"""
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive_fixture.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive_fixture.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/multiple_directive_fixture.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,15 @@
+import grokcore.site
+from zope import interface
+
+class IFireplace(interface.Interface):
+ pass
+
+class Fireplace(grokcore.site.LocalUtility):
+ interface.implements(IFireplace)
+
+class Fireplace2(grokcore.site.LocalUtility):
+ interface.implements(IFireplace)
+
+class Cave(grokcore.site.Site):
+ grokcore.site.local_utility(Fireplace, provides=IFireplace)
+ grokcore.site.local_utility(Fireplace2, provides=IFireplace)
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/publicnoncontainer.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/publicnoncontainer.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/tests/utility/publicnoncontainer.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,24 @@
+"""
+You cannot use local_utility with 'public' set to True if the site class
+isn't a container:
+
+ >>> grokcore.site.testing.grok(__name__)
+ Traceback (most recent call last):
+ ...
+ GrokError: Cannot set public to True with grok.local_utility as the site
+ (<class 'grokcore.site.tests.utility.publicnoncontainer.Cave'>) is not a container.
+
+"""
+import grokcore.site
+
+from zope import interface
+
+class IFireplace(interface.Interface):
+ pass
+
+class Fireplace(grokcore.site.LocalUtility):
+ interface.implements(IFireplace)
+
+class Cave(grokcore.site.Site):
+ grokcore.site.local_utility(Fireplace, public=True,
+ name_in_container='fireplace')
Added: grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/util.py
===================================================================
--- grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/util.py (rev 0)
+++ grokcore.registries/trunk/src/grokcore.site/src/grokcore/site/util.py 2012-05-02 09:49:03 UTC (rev 125599)
@@ -0,0 +1,64 @@
+##############################################################################
+#
+# Copyright (c) 2006-2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import grokcore.site
+from grokcore.site.interfaces import IApplication, ApplicationInitializedEvent
+from zope.component.hooks import getSite
+from zope.event import notify
+from zope.lifecycleevent import ObjectCreatedEvent
+
+
+def getApplication():
+ """Return the nearest enclosing :class:`grokcore.site.Application`.
+
+ Raises :exc:`ValueError` if no application can be found.
+ """
+ site = getSite()
+ if IApplication.providedBy(site):
+ return site
+ # Another sub-site is within the application. Walk up the object
+ # tree until we get to the an application.
+ obj = site
+ while obj is not None:
+ if IApplication.providedBy(obj):
+ return obj
+ obj = obj.__parent__
+ raise ValueError("No application found.")
+
+
+def create_application(factory, container, name):
+ """Creates an application and triggers the events from
+ the application lifecycle.
+ """
+ # Check the factory.
+ assert IApplication.implementedBy(factory)
+
+ # Check the availability of the name in the container.
+ if name in container:
+ raise KeyError(name)
+
+ # Instanciate the application
+ application = factory()
+
+ # Trigger the creation event.
+ notify(ObjectCreatedEvent(application))
+
+ # Persist the application.
+ # This may raise a KeyError.
+ container[name] = application
+
+ # Trigger the initialization event.
+ notify(ApplicationInitializedEvent(application))
+
+ return application
More information about the checkins
mailing list