Merge lp:~logan/ubuntu/raring/grokcore.component/2.5 into lp:ubuntu/raring/grokcore.component

Proposed by Logan Rosen
Status: Merged
Merged at revision: 4
Proposed branch: lp:~logan/ubuntu/raring/grokcore.component/2.5
Merge into: lp:ubuntu/raring/grokcore.component
Diff against target: 4788 lines (+2379/-1225)
51 files modified
CHANGES.txt (+59/-5)
COPYRIGHT.txt (+1/-10)
LICENSE.txt (+40/-50)
PKG-INFO (+251/-316)
README.txt (+23/-142)
bootstrap.py (+258/-0)
bootstrap/bootstrap.py (+0/-84)
buildout.cfg (+5/-4)
debian/changelog (+7/-0)
debian/control (+3/-6)
debian/pycompat (+0/-1)
debian/rules (+2/-5)
debian/source/format (+1/-0)
debian/watch (+2/-0)
setup.py (+9/-3)
src/grokcore.component.egg-info/PKG-INFO (+251/-316)
src/grokcore.component.egg-info/SOURCES.txt (+21/-3)
src/grokcore.component.egg-info/requires.txt (+5/-3)
src/grokcore/component/__init__.py (+51/-8)
src/grokcore/component/components.py (+86/-5)
src/grokcore/component/decorators.py (+38/-10)
src/grokcore/component/directive.py (+108/-7)
src/grokcore/component/interfaces.py (+80/-19)
src/grokcore/component/meta.py (+106/-70)
src/grokcore/component/subscription.py (+41/-0)
src/grokcore/component/testing.py (+1/-1)
src/grokcore/component/tests/adapter/globaladapter.py (+78/-19)
src/grokcore/component/tests/adapter/nomodel.py (+2/-1)
src/grokcore/component/tests/event/subscriber.py (+3/-3)
src/grokcore/component/tests/order/__init__.py (+1/-0)
src/grokcore/component/tests/order/arg_orderdirective.py (+42/-0)
src/grokcore/component/tests/order/combined_orderdirective.py (+34/-0)
src/grokcore/component/tests/order/combinednoorder_orderdirective.py (+34/-0)
src/grokcore/component/tests/order/inter1.py (+35/-0)
src/grokcore/component/tests/order/inter2.py (+14/-0)
src/grokcore/component/tests/order/noarg_orderdirective.py (+33/-0)
src/grokcore/component/tests/order/nodirective.py (+31/-0)
src/grokcore/component/tests/subscriptions/__init__.py (+1/-0)
src/grokcore/component/tests/subscriptions/decorator.py (+41/-0)
src/grokcore/component/tests/subscriptions/multisubscriptions.py (+98/-0)
src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py (+19/-0)
src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py (+20/-0)
src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py (+97/-0)
src/grokcore/component/tests/subscriptions/ordered_subscriptions.py (+71/-0)
src/grokcore/component/tests/subscriptions/subscriptions.py (+58/-0)
src/grokcore/component/tests/subscriptions/subscriptions_no_context.py (+20/-0)
src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py (+17/-0)
src/grokcore/component/tests/test_grok.py (+6/-4)
src/grokcore/component/util.py (+143/-0)
src/grokcore/component/zcml.py (+32/-15)
versions.cfg (+0/-115)
To merge this branch: bzr merge lp:~logan/ubuntu/raring/grokcore.component/2.5
Reviewer Review Type Date Requested Status
Daniel Holbach (community) Approve
Ubuntu branches Pending
Review via email: mp+144598@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Daniel Holbach (dholbach) wrote :

Thanks. Uploaded.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CHANGES.txt'
2--- CHANGES.txt 2010-01-29 16:22:17 +0000
3+++ CHANGES.txt 2013-01-23 22:26:20 +0000
4@@ -1,6 +1,61 @@
5 Changes
6 =======
7
8+2.5 (2012-05-01)
9+----------------
10+
11+- Introduce provideUtility, providerAdapter, provideSubscriptionAdapter,
12+ provideHandler and provideInterface in grokcore.component. These by default
13+ delegate the registration of components to the global site manager like
14+ was done before, but provide the possibility for custom registries for the
15+ grokked components.
16+
17+- Fix the `global_adapter` to properly use information annotated by
18+ ``grok.adapter``, and using the IContext object if it was not
19+ specified. (Fix Launchpad issue #960097).
20+
21+- Add a ``key`` option to ``sort_components`` that behave like ``key``
22+ options available on standard Python sort methods.
23+
24+2.4 (2011-04-27)
25+----------------
26+
27+- Fix the `global_adapter` directive implementation to accept an explicit
28+ "empty" name for nameless adapter registrations (as it used to be that
29+ providing an empty name in the registration would actually result in
30+ registering a named adapter in case the factory has a `grok.name`).
31+
32+2.3 (2011-02-14)
33+----------------
34+
35+- Implement the generic (Multi)Subscriptions components.
36+
37+2.2 (2010-11-03)
38+----------------
39+
40+- The default values computation for the context directive and the provides
41+ directive is now defined in the directives themselves. This means that where
42+ the values for these directives is being retrieved, the "default_context"
43+ function does not need to be passed along anymore for general cases.
44+
45+ Analogous to this, when getting values for the provides directive the
46+ "default_provides" function does not need to be passed along in the general
47+ case.
48+
49+2.1 (2010-11-01)
50+----------------
51+
52+* Made package comply to zope.org repository policy.
53+
54+* Moved directives 'order' from grokcore.viewlet and 'path' from
55+ grokcore.view to this very package.
56+
57+* Tiny dependency adjustment: moved zope.event to test dependencies.
58+
59+* Port from 1.x branch exclude parameter to the Grok ZCML directive.
60+
61+* Port from 1.x branch the ignore of testing.py modules.
62+
63 2.0 (2009-09-16)
64 ----------------
65
66@@ -26,7 +81,6 @@
67 * Add missing provider, global_adapter, implementsOnly, classProvides() to
68 the module interface so that they are included in __all__
69
70-
71 1.6 (2009-04-10)
72 ----------------
73
74@@ -36,7 +90,7 @@
75 * Add support for registering global adapters at module level::
76
77 grok.global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
78-
79+
80 Only 'factory' is required. If only a single interface is adapted, the
81 second argument may be a single interface instead of a tuple. If the
82 component has declared adapted/provided interfaces, the second and third
83@@ -44,11 +98,11 @@
84
85 * Add support for an @provider decorator to let a function directly provide
86 an interface::
87-
88+
89 @grok.provider(IFoo, IBar)
90 def some_function():
91 ...
92-
93+
94 This is equivalent to doing alsoProvides(some_function, IFoo, IBar).
95
96 * Add support for named adapters with the @adapter decorator::
97@@ -87,7 +141,7 @@
98 1.4 (2008-06-11)
99 ----------------
100
101-* Ported class grokkers to make use of further improvements in Martian.
102+* Ported class grokkers to make use of further improvements in Martian.
103 This requires Martian 0.10.
104
105 1.3 (2008-05-14)
106
107=== modified file 'COPYRIGHT.txt'
108--- COPYRIGHT.txt 2010-01-29 16:22:17 +0000
109+++ COPYRIGHT.txt 2013-01-23 22:26:20 +0000
110@@ -1,10 +1,1 @@
111-Copyright (c) 2008 gocept gmbh & co. kg, Martijn Faassen and Philipp von
112-Weitershausen
113-All Rights Reserved.
114-
115-This software is subject to the provisions of the Zope Public License,
116-Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
117-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
118-WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
119-WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
120-FOR A PARTICULAR PURPOSE.
121+Zope Foundation and Contributors
122\ No newline at end of file
123
124=== modified file 'LICENSE.txt'
125--- LICENSE.txt 2010-01-29 16:22:17 +0000
126+++ LICENSE.txt 2013-01-23 22:26:20 +0000
127@@ -1,54 +1,44 @@
128 Zope Public License (ZPL) Version 2.1
129--------------------------------------
130-
131-A copyright notice accompanies this license document that
132-identifies the copyright holders.
133-
134-This license has been certified as open source. It has also
135-been designated as GPL compatible by the Free Software
136-Foundation (FSF).
137-
138-Redistribution and use in source and binary forms, with or
139-without modification, are permitted provided that the
140-following conditions are met:
141-
142-1. Redistributions in source code must retain the
143- accompanying copyright notice, this list of conditions,
144- and the following disclaimer.
145-
146-2. Redistributions in binary form must reproduce the accompanying
147- copyright notice, this list of conditions, and the
148- following disclaimer in the documentation and/or other
149- materials provided with the distribution.
150-
151-3. Names of the copyright holders must not be used to
152- endorse or promote products derived from this software
153- without prior written permission from the copyright
154- holders.
155-
156-4. The right to distribute this software or to use it for
157- any purpose does not give you the right to use
158- Servicemarks (sm) or Trademarks (tm) of the copyright
159- holders. Use of them is covered by separate agreement
160- with the copyright holders.
161-
162-5. If any files are modified, you must cause the modified
163- files to carry prominent notices stating that you changed
164- the files and the date of any change.
165+
166+A copyright notice accompanies this license document that identifies the
167+copyright holders.
168+
169+This license has been certified as open source. It has also been designated as
170+GPL compatible by the Free Software Foundation (FSF).
171+
172+Redistribution and use in source and binary forms, with or without
173+modification, are permitted provided that the following conditions are met:
174+
175+1. Redistributions in source code must retain the accompanying copyright
176+notice, this list of conditions, and the following disclaimer.
177+
178+2. Redistributions in binary form must reproduce the accompanying copyright
179+notice, this list of conditions, and the following disclaimer in the
180+documentation and/or other materials provided with the distribution.
181+
182+3. Names of the copyright holders must not be used to endorse or promote
183+products derived from this software without prior written permission from the
184+copyright holders.
185+
186+4. The right to distribute this software or to use it for any purpose does not
187+give you the right to use Servicemarks (sm) or Trademarks (tm) of the
188+copyright
189+holders. Use of them is covered by separate agreement with the copyright
190+holders.
191+
192+5. If any files are modified, you must cause the modified files to carry
193+prominent notices stating that you changed the files and the date of any
194+change.
195
196 Disclaimer
197
198- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS''
199- AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
200- NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
201- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
202- NO EVENT SHALL THE COPYRIGHT HOLDERS BE
203- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
204- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
205- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
206- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
207- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
208- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
209- OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
210- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
211- DAMAGE.
212+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
213+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
214+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
215+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
216+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
217+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
218+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
219+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
220+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
221+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
222
223=== modified file 'PKG-INFO'
224--- PKG-INFO 2010-01-29 16:22:17 +0000
225+++ PKG-INFO 2013-01-23 22:26:20 +0000
226@@ -1,6 +1,6 @@
227 Metadata-Version: 1.0
228 Name: grokcore.component
229-Version: 2.0
230+Version: 2.5
231 Summary: Grok-like configuration for basic components (adapters, utilities, subscribers)
232 Home-page: http://grok.zope.org
233 Author: Grok Team
234@@ -29,34 +29,34 @@
235 we need to make sure it's available to the ZCML machinery. We do this
236 by including the meta configuration from ``grokcore.component``::
237
238- <include package="grokcore.component" file="meta.zcml" />
239+ <include package="grokcore.component" file="meta.zcml" />
240
241 Put this line somewhere to the top of ``site.zcml``, next to other
242 meta configuration includes. Now, further down the line, we can tell
243 the machinery in ``grokcore.component`` to register all components in
244 your package (let's say it's called ``helloworld``)::
245
246- <grok:grok package="helloworld" />
247+ <grok:grok package="helloworld" />
248
249 To sum up, your ``site.zcml`` file should look like something like this::
250
251- <configure
252- xmlns="http://namespaces.zope.org/zope"
253- xmlns:grok="http://namespaces.zope.org/grok">
254-
255- <!-- do the meta configuration to make the ZCML directives available -->
256- <include package="zope.foobar" file="meta.zcml" />
257- <include package="zope.frobnaz" file="meta.zcml" />
258- <include package="grokcore.component" file="meta.zcml" />
259-
260- <!-- now load the configuration of packages that we depend on -->
261- <include package="zope.barfoo" />
262- <include package="zope.somethingorother" />
263-
264- <!-- finally load my components which are based on grokcore.component -->
265- <grok:grok package="helloworld" />
266-
267- </configure>
268+ <configure
269+ xmlns="http://namespaces.zope.org/zope"
270+ xmlns:grok="http://namespaces.zope.org/grok">
271+
272+ <!-- do the meta configuration to make the ZCML directives available -->
273+ <include package="zope.foobar" file="meta.zcml" />
274+ <include package="zope.frobnaz" file="meta.zcml" />
275+ <include package="grokcore.component" file="meta.zcml" />
276+
277+ <!-- now load the configuration of packages that we depend on -->
278+ <include package="zope.barfoo" />
279+ <include package="zope.somethingorother" />
280+
281+ <!-- finally load my components which are based on grokcore.component -->
282+ <grok:grok package="helloworld" />
283+
284+ </configure>
285
286 Examples
287 ========
288@@ -67,26 +67,26 @@
289 Here's a simple adapter that may be useful in Zope. It extracts the
290 languages that a user prefers from the request::
291
292- import grokcore.component
293- from zope.publisher.interfaces.browser import IBrowserRequest
294- from zope.i18n.interfaces import IUserPreferredLanguages
295-
296- class CookieLanguage(grokcore.component.Adapter):
297- """Extract the preferred language from a cookie"""
298- grokcore.component.context(IBrowserRequest)
299- grokcore.component.implements(IUserPreferredLanguages)
300-
301- # No need to implement __init__, it's already provided by the base class.
302-
303- def getPreferredLanguages(self):
304- # This an adapter for the request, so self.context is the request.
305- request = self.context
306-
307- # Extract the preferred language from a cookie:
308- lang = request.cookies.get('language', 'en')
309-
310- # According to IUserPreferredLanguages, we must return a list.
311- return [lang]
312+ import grokcore.component
313+ from zope.publisher.interfaces.browser import IBrowserRequest
314+ from zope.i18n.interfaces import IUserPreferredLanguages
315+
316+ class CookieLanguage(grokcore.component.Adapter):
317+ """Extract the preferred language from a cookie"""
318+ grokcore.component.context(IBrowserRequest)
319+ grokcore.component.implements(IUserPreferredLanguages)
320+
321+ # No need to implement __init__, it's already provided by the base class.
322+
323+ def getPreferredLanguages(self):
324+ # This an adapter for the request, so self.context is the request.
325+ request = self.context
326+
327+ # Extract the preferred language from a cookie:
328+ lang = request.cookies.get('language', 'en')
329+
330+ # According to IUserPreferredLanguages, we must return a list.
331+ return [lang]
332
333 Multi-adapter
334 -------------
335@@ -97,21 +97,24 @@
336 the content object (model), the request and the view that they're
337 supposed to be a part of::
338
339- import grokcore.component
340- from zope.publisher.interfaces.browser import IBrowserRequest
341- from zope.publisher.interfaces.browser import IBrowserPage
342- from zope.contentprovider.interfaces import IContentProvider
343-
344- class HelloWorldProvider(grokcore.component.MultiAdapter):
345- """Display Hello World!"""
346- grokcore.component.adapts(Interface, IBrowserRequest, IBrowserPage)
347- grokcore.component.implements(IContentProvider)
348-
349- def update(self):
350- pass
351-
352- def render(self):
353- return u'<p>Hello World!</p>'
354+ import grokcore.component
355+ from zope.publisher.interfaces.browser import IBrowserRequest
356+ from zope.publisher.interfaces.browser import IBrowserPage
357+ from zope.contentprovider.interfaces import IContentProvider
358+
359+ class HelloWorldProvider(grokcore.component.MultiAdapter):
360+ """Display Hello World!"""
361+ grokcore.component.adapts(Interface, IBrowserRequest, IBrowserPage)
362+ grokcore.component.implements(IContentProvider)
363+
364+ def __init__(self, context, request, view):
365+ pass
366+
367+ def update(self):
368+ pass
369+
370+ def render(self):
371+ return u'<p>Hello World!</p>'
372
373
374 Global utility
375@@ -122,24 +125,24 @@
376 messages and is invoked when the i18n machinery needs to translate
377 something::
378
379- import grokcore.component
380- from zope.i18n.interfaces import ITranslationDomain
381-
382- class HelloWorldTranslationDomain(grokcore.component.GlobalUtility):
383- grokcore.component.implements(ITranslationDomain)
384- grokcore.component.name('helloworld')
385-
386- domain = u'helloworld'
387-
388- def translate(self, msgid, mapping=None, context=None,
389- target_language=None, default=None):
390- if target_language is None:
391- preferred = IUserPreferredLanguages(context)
392- target_language = preferred.getPreferredLanguages()[0]
393-
394- translations = {'de': u'Hallo Welt',
395- 'nl': u'Hallo Wereld'}
396- return translations.get(target_language, u'Hello World')
397+ import grokcore.component
398+ from zope.i18n.interfaces import ITranslationDomain
399+
400+ class HelloWorldTranslationDomain(grokcore.component.GlobalUtility):
401+ grokcore.component.implements(ITranslationDomain)
402+ grokcore.component.name('helloworld')
403+
404+ domain = u'helloworld'
405+
406+ def translate(self, msgid, mapping=None, context=None,
407+ target_language=None, default=None):
408+ if target_language is None:
409+ preferred = IUserPreferredLanguages(context)
410+ target_language = preferred.getPreferredLanguages()[0]
411+
412+ translations = {'de': u'Hallo Welt',
413+ 'nl': u'Hallo Wereld'}
414+ return translations.get(target_language, u'Hello World')
415
416 Of course, it's silly to implement your own translation domain utility
417 if there are already implementations available in ``zope.i18n`` (one
418@@ -147,18 +150,18 @@
419 simple implementation for tests). Let's try to reuse that
420 implementation and register an instance::
421
422- import grokcore.component
423- from zope.i18n.interfaces import ITranslationDomain
424- from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
425-
426- messages = {('de', u'Hello World'): u'Hallo Welt',
427- ('nl', u'Hello World'): u'Hallo Wereld'}
428- helloworld_domain = SimpleTranslationDomain(u'helloworld', messages)
429-
430- grokcore.component.global_utility(helloworld_domain,
431- provides=ITranslationDomain,
432- name='helloworld',
433- direct=True)
434+ import grokcore.component
435+ from zope.i18n.interfaces import ITranslationDomain
436+ from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
437+
438+ messages = {('de', u'Hello World'): u'Hallo Welt',
439+ ('nl', u'Hello World'): u'Hallo Wereld'}
440+ helloworld_domain = SimpleTranslationDomain(u'helloworld', messages)
441+
442+ grokcore.component.global_utility(helloworld_domain,
443+ provides=ITranslationDomain,
444+ name='helloworld',
445+ direct=True)
446
447 Global adapter
448 --------------
449@@ -172,333 +175,265 @@
450 example drawing on the ``z3c.form`` library, which provides an adapter factory
451 factory for named widget attributes::
452
453- import zope.interface
454- import zope.schema
455- import grokcore.component
456- import z3c.form.widget import ComputedWidgetAttribute
457-
458- class ISchema(Interface):
459- """This schema will be used to power a z3c.form form"""
460-
461- field = zope.schema.TextLine(title=u"Sample field")
462-
463- ...
464-
465- label_override = z3c.form.widget.StaticWidgetAttribute(
466- u"Override label", field=ISchema['field'])
467-
468- grokcore.component.global_adapter(label_override, name=u"label")
469+ import zope.interface
470+ import zope.schema
471+ import grokcore.component
472+ import z3c.form.widget import ComputedWidgetAttribute
473+
474+ class ISchema(Interface):
475+ """This schema will be used to power a z3c.form form"""
476+
477+ field = zope.schema.TextLine(title=u"Sample field")
478+
479+ ...
480+
481+ label_override = z3c.form.widget.StaticWidgetAttribute(
482+ u"Override label", field=ISchema['field'])
483+
484+ grokcore.component.global_adapter(label_override, name=u"label")
485
486 In the example above, the provided and adapted interfaces are deduced from the
487 object returned by the ``StaticWidgetAttribute`` factory. The full syntax
488 for global_adapter is::
489
490- global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
491+ global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
492
493 The factory must be a callable (the adapter factory). Adapted interfaces are
494 given as a tuple. You may use a single interface instead of a one-element
495 tuple for single adapters. The provided interface is given as shown. The name
496 defaults to u"" (an unnamed adapter).
497
498- Subscriber
499- ----------
500-
501- Here we see a subscriber much like it occurs within Zope itself. It
502- subscribes to the modified event for all annotatable objects (in other
503- words, objects that can have metadata associated with them). When
504- invoked, it updates the Dublin Core 'Modified' property accordingly::
505-
506- import datetime
507- import grokcore.component
508- from zope.annotation.interfaces import IAnnotatable
509- from zope.lifecycleevent.interfaces import IObjectModifiedEvent
510- from zope.dublincore.interfaces import IZopeDublinCore
511-
512- @grokcore.component.subscribe(IAnnotatable, IObjectModifiedEvent)
513- def updateDublinCoreAfterModification(obj, event):
514- """Updated the Dublin Core 'Modified' property when a modified
515- event is sent for an object."""
516- IZopeDublinCore(obj).modified = datetime.datetime.utcnow()
517-
518-
519- API overview
520- ============
521-
522- Base classes
523- ------------
524-
525- ``Adapter``
526- Base class for an adapter that adapts a single object (commonly
527- referred to as the *context*). Use the ``context`` directive to
528- specify which object to adapt and the ``implements`` directive to
529- specify which interface the adapter will provide. If it's a named
530- adapter, you may use the ``name`` directive to specify the name.
531-
532- ``MultiAdapter``
533- Base class for an adapter that adapts *n* objects (where *n>=1*).
534- Use the ``adapts`` directive to specify which kinds of objects are
535- adapted and the ``implements`` directive to specify which
536- interface the adapter will provide. If it's a named
537- multi-adapter, you may use the ``name`` directive to specify the
538- name.
539-
540- ``GlobalUtility``
541- Base class for a globally registered utility. Unless you use the
542- ``direct`` directive to indicate that the class itself should be
543- registered as a utility, the class will automatically be
544- instantiated, therefore the constructor may not take any
545- arguments. Use the ``implements`` directive to specify which
546- interface the utility provides, or if that is not unambiguous,
547- also use the ``provides`` directive to specify which of the
548- implemented interfaces should be used when registering the
549- utility. If it's a named utility, you may use the ``name``
550- directive to specify the name.
551-
552- ``Context``
553- Subclasses of this will automatically be found as potential
554- contexts for adapters and other types of context-dependent
555- components.
556-
557-
558- Class-level directives
559- ----------------------
560-
561- ``implements(iface1, iface2, ...)``
562- declares that a class implements the interfaces ``iface1``,
563- ``iface2``, etc. It is identical to
564- ``zope.interface.implements``.
565-
566- ``implementsOnly(iface1, iface2, ...)``
567- declares that a class *only* implements the interfaces ``iface1``,
568- ``iface2``, etc. It is identical to
569- ``zope.interface.implementsOnly``.
570-
571- ``classProvides(iface1, iface2, ...)``
572- declares that a class object (as opposed to instances of the class)
573- provides the interfaces ``iface1``, ``iface2``, etc. It is identical to
574- ``zope.interface.classProvides``.
575-
576- ``context(iface_or_class)``
577- declares the type of object that the adapter (or a similar
578- context-dependent component) adapts. This can either be an
579- interface (in this case all objects providing this interface will
580- be eligible contexts for the adapter) or a class (then only
581- instances of that particular class are eligible).
582-
583- ``adapts(iface_or_class1, iface_or_class_2, ...)``
584- declares the types of objects that a multi-adapter adapts.
585-
586- ``name(ascii_or_unicode)``
587- declares the name of a named utility, named adapter, etc.
588-
589- ``title(ascii_or_unicode)``
590- declares the human-readable title of a component (such as a
591- permission, role, etc.)
592-
593- ``provides(iface)``
594- declares the interface that a utility provides (as opposed to
595- potentially multiple interfaces that the class implements).
596-
597- ``direct()``
598- declares that a ``GlobalUtility`` class should be registered as a
599- utility itself, rather than an instance of it.
600-
601- ``baseclass()``
602- declares that a subclass of an otherwise automatically configured
603- component should not be registered, and that it serves as a base
604- class instead.
605-
606-
607- Module-level directives
608- -----------------------
609-
610- ``global_utility(class, [provides=iface, name=ascii_or_unicode, direct=bool])``
611- registers an instance of ``class`` (or ``class`` itself, depending
612- on the value of the ``direct`` parameter) as a global utility.
613- This allows you to register global utilities that don't inherit
614- from the ``GlobalUtility`` base class.
615-
616- ``global_adapter(factory, [adapts=tuple_of_interfaces, provides=iface, name=ascii_or_unicode])``
617- registers the ``factory`` callable as a global adapter. The ``adapts``
618- argument may be a tuple of interfaces or a single interface, if this is
619- a single adapter. Both ``adapts`` and ``provides`` will be deduced from
620- information annotated onto the factory if necessary. If no adapted
621- interface can be determined, the current context will be assumed. The
622- name defaults to u"". This allows you to register global adapters that
623- don't inherit from the ``Adapter`` or ``MultiAdapter`` base classes.
624-
625- Function decorators
626- -------------------
627-
628- ``@adapter(iface_or_class1, iface_or_class2, ..., name=u"name")``
629- registers the function as an adapter for the specific interface. The
630- ``name`` argument must be a keyword argument and is optional. If given,
631- a named adapter is registered.
632-
633- ``@implementer(iface1, iface2, ...)```
634- declares that the function implements a certain interface (or a
635- number of interfaces). This is useful when a function serves as an object
636- factory, e.g. as an adapter.
637-
638- ``@provider(iface1, iface2, ...)```
639- declares that the function object provides a certain interface (or a
640- number of interfaces). This is akin to calling directlyProvides() on
641- the function object.
642-
643- ``@subscribe(iface_or_class1, iface_or_class2, ...)``
644- declares that a function is to be registered as an event handler
645- for the specified objects. Normally, an event handler is simply
646- registered as a subscriber for the event interface. In case of
647- object events, the event handler is registered as a subscriber for
648- the object type and the event interface.
649+ Handling events
650+ ---------------
651+
652+ Here we see an event handler much like it occurs within Zope itself. It
653+ subscribes to the modified event for all annotatable objects (in other words,
654+ objects that can have metadata associated with them). When invoked, it updates
655+ the Dublin Core 'Modified' property accordingly::
656+
657+ import datetime
658+ import grokcore.component
659+ from zope.annotation.interfaces import IAnnotatable
660+ from zope.lifecycleevent.interfaces import IObjectModifiedEvent
661+ from zope.dublincore.interfaces import IZopeDublinCore
662+
663+ @grokcore.component.subscribe(IAnnotatable, IObjectModifiedEvent)
664+ def updateDublinCoreAfterModification(obj, event):
665+ """Updated the Dublin Core 'Modified' property when a modified
666+ event is sent for an object."""
667+ IZopeDublinCore(obj).modified = datetime.datetime.utcnow()
668+
669+ Subscriptions
670+ -------------
671+
672+ Subscriptions look similar to Adapter, however, unlike regular adapters,
673+ subscription adapters are used when we want all of the adapters that adapt an
674+ object to a particular adapter.
675+
676+ Analogous to MultiAdapter, there is a MultiSubscription component that "adapts"
677+ multiple objects.
678
679 Changes
680 =======
681
682+ 2.5 (2012-05-01)
683+ ----------------
684+
685+ - Introduce provideUtility, providerAdapter, provideSubscriptionAdapter,
686+ provideHandler and provideInterface in grokcore.component. These by default
687+ delegate the registration of components to the global site manager like
688+ was done before, but provide the possibility for custom registries for the
689+ grokked components.
690+
691+ - Fix the `global_adapter` to properly use information annotated by
692+ ``grok.adapter``, and using the IContext object if it was not
693+ specified. (Fix Launchpad issue #960097).
694+
695+ - Add a ``key`` option to ``sort_components`` that behave like ``key``
696+ options available on standard Python sort methods.
697+
698+ 2.4 (2011-04-27)
699+ ----------------
700+
701+ - Fix the `global_adapter` directive implementation to accept an explicit
702+ "empty" name for nameless adapter registrations (as it used to be that
703+ providing an empty name in the registration would actually result in
704+ registering a named adapter in case the factory has a `grok.name`).
705+
706+ 2.3 (2011-02-14)
707+ ----------------
708+
709+ - Implement the generic (Multi)Subscriptions components.
710+
711+ 2.2 (2010-11-03)
712+ ----------------
713+
714+ - The default values computation for the context directive and the provides
715+ directive is now defined in the directives themselves. This means that where
716+ the values for these directives is being retrieved, the "default_context"
717+ function does not need to be passed along anymore for general cases.
718+
719+ Analogous to this, when getting values for the provides directive the
720+ "default_provides" function does not need to be passed along in the general
721+ case.
722+
723+ 2.1 (2010-11-01)
724+ ----------------
725+
726+ * Made package comply to zope.org repository policy.
727+
728+ * Moved directives 'order' from grokcore.viewlet and 'path' from
729+ grokcore.view to this very package.
730+
731+ * Tiny dependency adjustment: moved zope.event to test dependencies.
732+
733+ * Port from 1.x branch exclude parameter to the Grok ZCML directive.
734+
735+ * Port from 1.x branch the ignore of testing.py modules.
736+
737 2.0 (2009-09-16)
738 ----------------
739
740 * Use a newer version of Martian that has better support for
741- inheritance. This is demonstrated in ``tests/inherit``.
742+ inheritance. This is demonstrated in ``tests/inherit``.
743
744 * The ``ContextGrokker`` and the ``scan.py`` module have gone away
745- thanks the newer Martian.
746+ thanks the newer Martian.
747
748 * Directive implementations (in their factory method) should *not*
749- bind directives. Directive binding cannot take place at import time,
750- but only at grok time. Binding directives during import time (when
751- directives are executed) can lead to change problems. (we noticed
752- this during our refactoring to use the new Martian).
753+ bind directives. Directive binding cannot take place at import time,
754+ but only at grok time. Binding directives during import time (when
755+ directives are executed) can lead to change problems. (we noticed
756+ this during our refactoring to use the new Martian).
757
758 * Use 1.0b1 versions.cfg in Grok's release info instead of a local
759- copy; a local copy for all grokcore packages is just too hard to
760- maintain.
761+ copy; a local copy for all grokcore packages is just too hard to
762+ maintain.
763
764 1.7 (2009-06-01)
765 ----------------
766
767 * Add missing provider, global_adapter, implementsOnly, classProvides() to
768- the module interface so that they are included in __all__
769-
770+ the module interface so that they are included in __all__
771
772 1.6 (2009-04-10)
773 ----------------
774
775 * Add convenience imports for implementsOnly() and classProvides() class
776- declarations form zope.interface.
777+ declarations form zope.interface.
778
779 * Add support for registering global adapters at module level::
780
781- grok.global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
782+ grok.global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
783
784- Only 'factory' is required. If only a single interface is adapted, the
785- second argument may be a single interface instead of a tuple. If the
786- component has declared adapted/provided interfaces, the second and third
787- arguments may be omitted.
788+ Only 'factory' is required. If only a single interface is adapted, the
789+ second argument may be a single interface instead of a tuple. If the
790+ component has declared adapted/provided interfaces, the second and third
791+ arguments may be omitted.
792
793 * Add support for an @provider decorator to let a function directly provide
794- an interface::
795-
796- @grok.provider(IFoo, IBar)
797- def some_function():
798- ...
799-
800- This is equivalent to doing alsoProvides(some_function, IFoo, IBar).
801+ an interface::
802+
803+ @grok.provider(IFoo, IBar)
804+ def some_function():
805+ ...
806+
807+ This is equivalent to doing alsoProvides(some_function, IFoo, IBar).
808
809 * Add support for named adapters with the @adapter decorator::
810
811- @grok.adapter(IAdaptedOne, IAdaptedTwo, name=u"foo")
812- def some_function(one, two):
813- ...
814+ @grok.adapter(IAdaptedOne, IAdaptedTwo, name=u"foo")
815+ def some_function(one, two):
816+ ...
817
818 1.5.1 (2008-07-28)
819 ------------------
820
821 * The ``IGrokcoreComponentAPI`` interface was missing declarations for
822- the ``title`` and ``description`` directives.
823+ the ``title`` and ``description`` directives.
824
825 1.5 (2008-07-22)
826 ----------------
827
828 * Fix https://bugs.launchpad.net/grok/+bug/242353: grokcore.component
829- contains old-style test setup. There is no `register_all_tests`
830- method in grokcore.component.testing anymore. Use z3c.testsetup
831- instead.
832+ contains old-style test setup. There is no `register_all_tests`
833+ method in grokcore.component.testing anymore. Use z3c.testsetup
834+ instead.
835
836 * Allow functions that have been marked with @grok.subscribe also be
837- registered with ``zope.component.provideHandler()`` manually. This
838- is useful for unit tests where you may not want to grok a whole
839- module.
840+ registered with ``zope.component.provideHandler()`` manually. This
841+ is useful for unit tests where you may not want to grok a whole
842+ module.
843
844 * Document grokcore.component's public API in an interface,
845- ``IGrokcoreComponentAPI``. When you now do::
846-
847- from grokcore.component import *
848-
849- only the items documented in that interface will be imported into
850- your local namespace.
851+ ``IGrokcoreComponentAPI``. When you now do::
852+
853+ from grokcore.component import *
854+
855+ only the items documented in that interface will be imported into
856+ your local namespace.
857
858 1.4 (2008-06-11)
859 ----------------
860
861 * Ported class grokkers to make use of further improvements in Martian.
862- This requires Martian 0.10.
863+ This requires Martian 0.10.
864
865 1.3 (2008-05-14)
866 ----------------
867
868 * Ported class grokkers to make use of the new declarative way of
869- retrieving directive information from a class. This requires
870- Martian 0.9.6.
871+ retrieving directive information from a class. This requires
872+ Martian 0.9.6.
873
874 1.2.1 (2008-05-04)
875 ------------------
876
877 * Upgrade to Martian 0.9.5, which has a slight change in the signature of
878- ``scan_for_classes``.
879+ ``scan_for_classes``.
880
881 * Remove an unnecessary import ``methods_from_class`` from
882- ``grokcore.component.scan``.
883+ ``grokcore.component.scan``.
884
885 1.2 (2008-05-04)
886 ----------------
887
888 * Ported directives to Martian's new directive implementation. As a
889- result, nearly all helper functions that were available from
890- ``grokcore.component.util`` have been removed. The functionality is
891- mostly available from the directives themselves now.
892+ result, nearly all helper functions that were available from
893+ ``grokcore.component.util`` have been removed. The functionality is
894+ mostly available from the directives themselves now.
895
896 * The ``baseclass`` directive has been moved to Martian.
897
898 * The ``order`` directive and its helper functions have been moved
899- back to Grok, as it was of no general use, but very specific to
900- viewlets.
901+ back to Grok, as it was of no general use, but very specific to
902+ viewlets.
903
904 1.1 (2008-05-03)
905 ----------------
906
907 * ``determine_module_component`` now looks for classes that implement
908- a certain interface (such as ``IContext``), instead of taking a list
909- of classes. If looking for ``IContext``, it still will find
910- ``Context`` subclasses, as these were also made to implement
911- ``IContext``.
912+ a certain interface (such as ``IContext``), instead of taking a list
913+ of classes. If looking for ``IContext``, it still will find
914+ ``Context`` subclasses, as these were also made to implement
915+ ``IContext``.
916
917 * Move the ``public_methods_from_class`` helper function back to Grok,
918- it isn't used at all in ``grokcore.component``.
919+ it isn't used at all in ``grokcore.component``.
920
921 1.0.1 (2008-05-02)
922 ------------------
923
924 * The grokkers for adapters and global utilities did not use the
925- correct value for the *provided* interface in the configuration
926- action discriminator. Because of this, uninformative and
927- potentially wrong conflict errors would occur, as well as no
928- conflict where a conflict should have occurred.
929+ correct value for the *provided* interface in the configuration
930+ action discriminator. Because of this, uninformative and
931+ potentially wrong conflict errors would occur, as well as no
932+ conflict where a conflict should have occurred.
933
934 * The grokker for the ``global_utility()`` directive did immediate
935- registrations instead of generating configuration actions.
936- Therefore it did not provoke ``ConflictErrors`` for conflicting
937- registrations.
938+ registrations instead of generating configuration actions.
939+ Therefore it did not provoke ``ConflictErrors`` for conflicting
940+ registrations.
941
942 * Improved documentation
943
944@@ -506,8 +441,8 @@
945 ----------------
946
947 * Created ``grokcore.component`` in March 2008 by factoring basic
948- component base classes and their directives and grokkers out of
949- Grok.
950+ component base classes and their directives and grokkers out of
951+ Grok.
952
953 Platform: UNKNOWN
954 Classifier: Intended Audience :: Developers
955
956=== modified file 'README.txt'
957--- README.txt 2010-01-29 16:22:17 +0000
958+++ README.txt 2013-01-23 22:26:20 +0000
959@@ -98,6 +98,9 @@
960 grokcore.component.adapts(Interface, IBrowserRequest, IBrowserPage)
961 grokcore.component.implements(IContentProvider)
962
963+ def __init__(self, context, request, view):
964+ pass
965+
966 def update(self):
967 pass
968
969@@ -170,34 +173,34 @@
970
971 class ISchema(Interface):
972 """This schema will be used to power a z3c.form form"""
973-
974+
975 field = zope.schema.TextLine(title=u"Sample field")
976-
977+
978 ...
979
980 label_override = z3c.form.widget.StaticWidgetAttribute(
981 u"Override label", field=ISchema['field'])
982-
983+
984 grokcore.component.global_adapter(label_override, name=u"label")
985-
986+
987 In the example above, the provided and adapted interfaces are deduced from the
988 object returned by the ``StaticWidgetAttribute`` factory. The full syntax
989 for global_adapter is::
990
991 global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
992-
993+
994 The factory must be a callable (the adapter factory). Adapted interfaces are
995 given as a tuple. You may use a single interface instead of a one-element
996 tuple for single adapters. The provided interface is given as shown. The name
997 defaults to u"" (an unnamed adapter).
998
999-Subscriber
1000-----------
1001+Handling events
1002+---------------
1003
1004-Here we see a subscriber much like it occurs within Zope itself. It
1005-subscribes to the modified event for all annotatable objects (in other
1006-words, objects that can have metadata associated with them). When
1007-invoked, it updates the Dublin Core 'Modified' property accordingly::
1008+Here we see an event handler much like it occurs within Zope itself. It
1009+subscribes to the modified event for all annotatable objects (in other words,
1010+objects that can have metadata associated with them). When invoked, it updates
1011+the Dublin Core 'Modified' property accordingly::
1012
1013 import datetime
1014 import grokcore.component
1015@@ -211,134 +214,12 @@
1016 event is sent for an object."""
1017 IZopeDublinCore(obj).modified = datetime.datetime.utcnow()
1018
1019-
1020-API overview
1021-============
1022-
1023-Base classes
1024-------------
1025-
1026-``Adapter``
1027- Base class for an adapter that adapts a single object (commonly
1028- referred to as the *context*). Use the ``context`` directive to
1029- specify which object to adapt and the ``implements`` directive to
1030- specify which interface the adapter will provide. If it's a named
1031- adapter, you may use the ``name`` directive to specify the name.
1032-
1033-``MultiAdapter``
1034- Base class for an adapter that adapts *n* objects (where *n>=1*).
1035- Use the ``adapts`` directive to specify which kinds of objects are
1036- adapted and the ``implements`` directive to specify which
1037- interface the adapter will provide. If it's a named
1038- multi-adapter, you may use the ``name`` directive to specify the
1039- name.
1040-
1041-``GlobalUtility``
1042- Base class for a globally registered utility. Unless you use the
1043- ``direct`` directive to indicate that the class itself should be
1044- registered as a utility, the class will automatically be
1045- instantiated, therefore the constructor may not take any
1046- arguments. Use the ``implements`` directive to specify which
1047- interface the utility provides, or if that is not unambiguous,
1048- also use the ``provides`` directive to specify which of the
1049- implemented interfaces should be used when registering the
1050- utility. If it's a named utility, you may use the ``name``
1051- directive to specify the name.
1052-
1053-``Context``
1054- Subclasses of this will automatically be found as potential
1055- contexts for adapters and other types of context-dependent
1056- components.
1057-
1058-
1059-Class-level directives
1060-----------------------
1061-
1062-``implements(iface1, iface2, ...)``
1063- declares that a class implements the interfaces ``iface1``,
1064- ``iface2``, etc. It is identical to
1065- ``zope.interface.implements``.
1066-
1067-``implementsOnly(iface1, iface2, ...)``
1068- declares that a class *only* implements the interfaces ``iface1``,
1069- ``iface2``, etc. It is identical to
1070- ``zope.interface.implementsOnly``.
1071-
1072-``classProvides(iface1, iface2, ...)``
1073- declares that a class object (as opposed to instances of the class)
1074- provides the interfaces ``iface1``, ``iface2``, etc. It is identical to
1075- ``zope.interface.classProvides``.
1076-
1077-``context(iface_or_class)``
1078- declares the type of object that the adapter (or a similar
1079- context-dependent component) adapts. This can either be an
1080- interface (in this case all objects providing this interface will
1081- be eligible contexts for the adapter) or a class (then only
1082- instances of that particular class are eligible).
1083-
1084-``adapts(iface_or_class1, iface_or_class_2, ...)``
1085- declares the types of objects that a multi-adapter adapts.
1086-
1087-``name(ascii_or_unicode)``
1088- declares the name of a named utility, named adapter, etc.
1089-
1090-``title(ascii_or_unicode)``
1091- declares the human-readable title of a component (such as a
1092- permission, role, etc.)
1093-
1094-``provides(iface)``
1095- declares the interface that a utility provides (as opposed to
1096- potentially multiple interfaces that the class implements).
1097-
1098-``direct()``
1099- declares that a ``GlobalUtility`` class should be registered as a
1100- utility itself, rather than an instance of it.
1101-
1102-``baseclass()``
1103- declares that a subclass of an otherwise automatically configured
1104- component should not be registered, and that it serves as a base
1105- class instead.
1106-
1107-
1108-Module-level directives
1109------------------------
1110-
1111-``global_utility(class, [provides=iface, name=ascii_or_unicode, direct=bool])``
1112- registers an instance of ``class`` (or ``class`` itself, depending
1113- on the value of the ``direct`` parameter) as a global utility.
1114- This allows you to register global utilities that don't inherit
1115- from the ``GlobalUtility`` base class.
1116-
1117-``global_adapter(factory, [adapts=tuple_of_interfaces, provides=iface, name=ascii_or_unicode])``
1118- registers the ``factory`` callable as a global adapter. The ``adapts``
1119- argument may be a tuple of interfaces or a single interface, if this is
1120- a single adapter. Both ``adapts`` and ``provides`` will be deduced from
1121- information annotated onto the factory if necessary. If no adapted
1122- interface can be determined, the current context will be assumed. The
1123- name defaults to u"". This allows you to register global adapters that
1124- don't inherit from the ``Adapter`` or ``MultiAdapter`` base classes.
1125-
1126-Function decorators
1127--------------------
1128-
1129-``@adapter(iface_or_class1, iface_or_class2, ..., name=u"name")``
1130- registers the function as an adapter for the specific interface. The
1131- ``name`` argument must be a keyword argument and is optional. If given,
1132- a named adapter is registered.
1133-
1134-``@implementer(iface1, iface2, ...)```
1135- declares that the function implements a certain interface (or a
1136- number of interfaces). This is useful when a function serves as an object
1137- factory, e.g. as an adapter.
1138-
1139-``@provider(iface1, iface2, ...)```
1140- declares that the function object provides a certain interface (or a
1141- number of interfaces). This is akin to calling directlyProvides() on
1142- the function object.
1143-
1144-``@subscribe(iface_or_class1, iface_or_class2, ...)``
1145- declares that a function is to be registered as an event handler
1146- for the specified objects. Normally, an event handler is simply
1147- registered as a subscriber for the event interface. In case of
1148- object events, the event handler is registered as a subscriber for
1149- the object type and the event interface.
1150+Subscriptions
1151+-------------
1152+
1153+Subscriptions look similar to Adapter, however, unlike regular adapters,
1154+subscription adapters are used when we want all of the adapters that adapt an
1155+object to a particular adapter.
1156+
1157+Analogous to MultiAdapter, there is a MultiSubscription component that "adapts"
1158+multiple objects.
1159
1160=== removed directory 'bootstrap'
1161=== added file 'bootstrap.py'
1162--- bootstrap.py 1970-01-01 00:00:00 +0000
1163+++ bootstrap.py 2013-01-23 22:26:20 +0000
1164@@ -0,0 +1,258 @@
1165+##############################################################################
1166+#
1167+# Copyright (c) 2006 Zope Foundation and Contributors.
1168+# All Rights Reserved.
1169+#
1170+# This software is subject to the provisions of the Zope Public License,
1171+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
1172+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
1173+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1174+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
1175+# FOR A PARTICULAR PURPOSE.
1176+#
1177+##############################################################################
1178+"""Bootstrap a buildout-based project
1179+
1180+Simply run this script in a directory containing a buildout.cfg.
1181+The script accepts buildout command-line options, so you can
1182+use the -c option to specify an alternate configuration file.
1183+"""
1184+
1185+import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
1186+from optparse import OptionParser
1187+
1188+if sys.platform == 'win32':
1189+ def quote(c):
1190+ if ' ' in c:
1191+ return '"%s"' % c # work around spawn lamosity on windows
1192+ else:
1193+ return c
1194+else:
1195+ quote = str
1196+
1197+# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
1198+stdout, stderr = subprocess.Popen(
1199+ [sys.executable, '-Sc',
1200+ 'try:\n'
1201+ ' import ConfigParser\n'
1202+ 'except ImportError:\n'
1203+ ' print 1\n'
1204+ 'else:\n'
1205+ ' print 0\n'],
1206+ stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
1207+has_broken_dash_S = bool(int(stdout.strip()))
1208+
1209+# In order to be more robust in the face of system Pythons, we want to
1210+# run without site-packages loaded. This is somewhat tricky, in
1211+# particular because Python 2.6's distutils imports site, so starting
1212+# with the -S flag is not sufficient. However, we'll start with that:
1213+if not has_broken_dash_S and 'site' in sys.modules:
1214+ # We will restart with python -S.
1215+ args = sys.argv[:]
1216+ args[0:0] = [sys.executable, '-S']
1217+ args = map(quote, args)
1218+ os.execv(sys.executable, args)
1219+# Now we are running with -S. We'll get the clean sys.path, import site
1220+# because distutils will do it later, and then reset the path and clean
1221+# out any namespace packages from site-packages that might have been
1222+# loaded by .pth files.
1223+clean_path = sys.path[:]
1224+import site
1225+sys.path[:] = clean_path
1226+for k, v in sys.modules.items():
1227+ if (hasattr(v, '__path__') and
1228+ len(v.__path__)==1 and
1229+ not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
1230+ # This is a namespace package. Remove it.
1231+ sys.modules.pop(k)
1232+
1233+is_jython = sys.platform.startswith('java')
1234+
1235+setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
1236+distribute_source = 'http://python-distribute.org/distribute_setup.py'
1237+
1238+# parsing arguments
1239+def normalize_to_url(option, opt_str, value, parser):
1240+ if value:
1241+ if '://' not in value: # It doesn't smell like a URL.
1242+ value = 'file://%s' % (
1243+ urllib.pathname2url(
1244+ os.path.abspath(os.path.expanduser(value))),)
1245+ if opt_str == '--download-base' and not value.endswith('/'):
1246+ # Download base needs a trailing slash to make the world happy.
1247+ value += '/'
1248+ else:
1249+ value = None
1250+ name = opt_str[2:].replace('-', '_')
1251+ setattr(parser.values, name, value)
1252+
1253+usage = '''\
1254+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
1255+
1256+Bootstraps a buildout-based project.
1257+
1258+Simply run this script in a directory containing a buildout.cfg, using the
1259+Python that you want bin/buildout to use.
1260+
1261+Note that by using --setup-source and --download-base to point to
1262+local resources, you can keep this script from going over the network.
1263+'''
1264+
1265+parser = OptionParser(usage=usage)
1266+parser.add_option("-v", "--version", dest="version",
1267+ help="use a specific zc.buildout version")
1268+parser.add_option("-d", "--distribute",
1269+ action="store_true", dest="use_distribute", default=False,
1270+ help="Use Distribute rather than Setuptools.")
1271+parser.add_option("--setup-source", action="callback", dest="setup_source",
1272+ callback=normalize_to_url, nargs=1, type="string",
1273+ help=("Specify a URL or file location for the setup file. "
1274+ "If you use Setuptools, this will default to " +
1275+ setuptools_source + "; if you use Distribute, this "
1276+ "will default to " + distribute_source +"."))
1277+parser.add_option("--download-base", action="callback", dest="download_base",
1278+ callback=normalize_to_url, nargs=1, type="string",
1279+ help=("Specify a URL or directory for downloading "
1280+ "zc.buildout and either Setuptools or Distribute. "
1281+ "Defaults to PyPI."))
1282+parser.add_option("--eggs",
1283+ help=("Specify a directory for storing eggs. Defaults to "
1284+ "a temporary directory that is deleted when the "
1285+ "bootstrap script completes."))
1286+parser.add_option("-t", "--accept-buildout-test-releases",
1287+ dest='accept_buildout_test_releases',
1288+ action="store_true", default=False,
1289+ help=("Normally, if you do not specify a --version, the "
1290+ "bootstrap script and buildout gets the newest "
1291+ "*final* versions of zc.buildout and its recipes and "
1292+ "extensions for you. If you use this flag, "
1293+ "bootstrap and buildout will get the newest releases "
1294+ "even if they are alphas or betas."))
1295+parser.add_option("-c", None, action="store", dest="config_file",
1296+ help=("Specify the path to the buildout configuration "
1297+ "file to be used."))
1298+
1299+options, args = parser.parse_args()
1300+
1301+# if -c was provided, we push it back into args for buildout's main function
1302+if options.config_file is not None:
1303+ args += ['-c', options.config_file]
1304+
1305+if options.eggs:
1306+ eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
1307+else:
1308+ eggs_dir = tempfile.mkdtemp()
1309+
1310+if options.setup_source is None:
1311+ if options.use_distribute:
1312+ options.setup_source = distribute_source
1313+ else:
1314+ options.setup_source = setuptools_source
1315+
1316+if options.accept_buildout_test_releases:
1317+ args.append('buildout:accept-buildout-test-releases=true')
1318+args.append('bootstrap')
1319+
1320+try:
1321+ import pkg_resources
1322+ import setuptools # A flag. Sometimes pkg_resources is installed alone.
1323+ if not hasattr(pkg_resources, '_distribute'):
1324+ raise ImportError
1325+except ImportError:
1326+ ez_code = urllib2.urlopen(
1327+ options.setup_source).read().replace('\r\n', '\n')
1328+ ez = {}
1329+ exec ez_code in ez
1330+ setup_args = dict(to_dir=eggs_dir, download_delay=0)
1331+ if options.download_base:
1332+ setup_args['download_base'] = options.download_base
1333+ if options.use_distribute:
1334+ setup_args['no_fake'] = True
1335+ ez['use_setuptools'](**setup_args)
1336+ reload(sys.modules['pkg_resources'])
1337+ import pkg_resources
1338+ # This does not (always?) update the default working set. We will
1339+ # do it.
1340+ for path in sys.path:
1341+ if path not in pkg_resources.working_set.entries:
1342+ pkg_resources.working_set.add_entry(path)
1343+
1344+cmd = [quote(sys.executable),
1345+ '-c',
1346+ quote('from setuptools.command.easy_install import main; main()'),
1347+ '-mqNxd',
1348+ quote(eggs_dir)]
1349+
1350+if not has_broken_dash_S:
1351+ cmd.insert(1, '-S')
1352+
1353+find_links = options.download_base
1354+if not find_links:
1355+ find_links = os.environ.get('bootstrap-testing-find-links')
1356+if find_links:
1357+ cmd.extend(['-f', quote(find_links)])
1358+
1359+if options.use_distribute:
1360+ setup_requirement = 'distribute'
1361+else:
1362+ setup_requirement = 'setuptools'
1363+ws = pkg_resources.working_set
1364+setup_requirement_path = ws.find(
1365+ pkg_resources.Requirement.parse(setup_requirement)).location
1366+env = dict(
1367+ os.environ,
1368+ PYTHONPATH=setup_requirement_path)
1369+
1370+requirement = 'zc.buildout'
1371+version = options.version
1372+if version is None and not options.accept_buildout_test_releases:
1373+ # Figure out the most recent final version of zc.buildout.
1374+ import setuptools.package_index
1375+ _final_parts = '*final-', '*final'
1376+ def _final_version(parsed_version):
1377+ for part in parsed_version:
1378+ if (part[:1] == '*') and (part not in _final_parts):
1379+ return False
1380+ return True
1381+ index = setuptools.package_index.PackageIndex(
1382+ search_path=[setup_requirement_path])
1383+ if find_links:
1384+ index.add_find_links((find_links,))
1385+ req = pkg_resources.Requirement.parse(requirement)
1386+ if index.obtain(req) is not None:
1387+ best = []
1388+ bestv = None
1389+ for dist in index[req.project_name]:
1390+ distv = dist.parsed_version
1391+ if _final_version(distv):
1392+ if bestv is None or distv > bestv:
1393+ best = [dist]
1394+ bestv = distv
1395+ elif distv == bestv:
1396+ best.append(dist)
1397+ if best:
1398+ best.sort()
1399+ version = best[-1].version
1400+if version:
1401+ requirement = '=='.join((requirement, version))
1402+cmd.append(requirement)
1403+
1404+if is_jython:
1405+ import subprocess
1406+ exitcode = subprocess.Popen(cmd, env=env).wait()
1407+else: # Windows prefers this, apparently; otherwise we would prefer subprocess
1408+ exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
1409+if exitcode != 0:
1410+ sys.stdout.flush()
1411+ sys.stderr.flush()
1412+ print ("An error occurred when trying to install zc.buildout. "
1413+ "Look above this message for any errors that "
1414+ "were output by easy_install.")
1415+ sys.exit(exitcode)
1416+
1417+ws.add_entry(eggs_dir)
1418+ws.require(requirement)
1419+import zc.buildout.buildout
1420+zc.buildout.buildout.main(args)
1421+if not options.eggs: # clean up temporary egg directory
1422+ shutil.rmtree(eggs_dir)
1423
1424=== removed file 'bootstrap/bootstrap.py'
1425--- bootstrap/bootstrap.py 2010-01-29 16:22:17 +0000
1426+++ bootstrap/bootstrap.py 1970-01-01 00:00:00 +0000
1427@@ -1,84 +0,0 @@
1428-##############################################################################
1429-#
1430-# Copyright (c) 2006 Zope Corporation and Contributors.
1431-# All Rights Reserved.
1432-#
1433-# This software is subject to the provisions of the Zope Public License,
1434-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
1435-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
1436-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1437-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
1438-# FOR A PARTICULAR PURPOSE.
1439-#
1440-##############################################################################
1441-"""Bootstrap a buildout-based project
1442-
1443-Simply run this script in a directory containing a buildout.cfg.
1444-The script accepts buildout command-line options, so you can
1445-use the -c option to specify an alternate configuration file.
1446-
1447-$Id: bootstrap.py 102545 2009-08-06 14:49:47Z chrisw $
1448-"""
1449-
1450-import os, shutil, sys, tempfile, urllib2
1451-
1452-tmpeggs = tempfile.mkdtemp()
1453-
1454-is_jython = sys.platform.startswith('java')
1455-
1456-try:
1457- import pkg_resources
1458-except ImportError:
1459- ez = {}
1460- exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
1461- ).read() in ez
1462- ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
1463-
1464- import pkg_resources
1465-
1466-if sys.platform == 'win32':
1467- def quote(c):
1468- if ' ' in c:
1469- return '"%s"' % c # work around spawn lamosity on windows
1470- else:
1471- return c
1472-else:
1473- def quote (c):
1474- return c
1475-
1476-cmd = 'from setuptools.command.easy_install import main; main()'
1477-ws = pkg_resources.working_set
1478-
1479-if len(sys.argv) > 2 and sys.argv[1] == '--version':
1480- VERSION = '==%s' % sys.argv[2]
1481- args = sys.argv[3:] + ['bootstrap']
1482-else:
1483- VERSION = ''
1484- args = sys.argv[1:] + ['bootstrap']
1485-
1486-if is_jython:
1487- import subprocess
1488-
1489- assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
1490- quote(tmpeggs), 'zc.buildout' + VERSION],
1491- env=dict(os.environ,
1492- PYTHONPATH=
1493- ws.find(pkg_resources.Requirement.parse('setuptools')).location
1494- ),
1495- ).wait() == 0
1496-
1497-else:
1498- assert os.spawnle(
1499- os.P_WAIT, sys.executable, quote (sys.executable),
1500- '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION,
1501- dict(os.environ,
1502- PYTHONPATH=
1503- ws.find(pkg_resources.Requirement.parse('setuptools')).location
1504- ),
1505- ) == 0
1506-
1507-ws.add_entry(tmpeggs)
1508-ws.require('zc.buildout' + VERSION)
1509-import zc.buildout.buildout
1510-zc.buildout.buildout.main(args)
1511-shutil.rmtree(tmpeggs)
1512
1513=== modified file 'buildout.cfg'
1514--- buildout.cfg 2010-01-29 16:22:17 +0000
1515+++ buildout.cfg 2013-01-23 22:26:20 +0000
1516@@ -1,12 +1,12 @@
1517 [buildout]
1518 develop = .
1519 parts = interpreter test
1520-extends = http://grok.zope.org/releaseinfo/grok-1.0b1.cfg
1521+extends = http://svn.zope.org/repos/main/groktoolkit/trunk/grok.cfg
1522 versions = versions
1523+extensions = buildout.dumppickedversions
1524
1525 [versions]
1526-martian = 0.12
1527-grokcore.component =
1528+grokcore.component =
1529
1530 [interpreter]
1531 recipe = zc.recipe.egg
1532@@ -16,4 +16,5 @@
1533 [test]
1534 recipe = zc.recipe.testrunner
1535 eggs = grokcore.component
1536-defaults = ['--tests-pattern', '^f?tests$', '-v']
1537+ grokcore.component[test]
1538+defaults = ['--tests-pattern', '^f?tests$', '-v', '--auto-color']
1539
1540=== modified file 'debian/changelog'
1541--- debian/changelog 2011-09-11 16:48:22 +0000
1542+++ debian/changelog 2013-01-23 22:26:20 +0000
1543@@ -1,3 +1,10 @@
1544+grokcore.component (2.5-0ubuntu1) raring; urgency=low
1545+
1546+ * New upstream release.
1547+ * Convert to dh_python2 and quilt.
1548+
1549+ -- Logan Rosen <logatronico@gmail.com> Wed, 23 Jan 2013 17:14:27 -0500
1550+
1551 grokcore.component (2.0-0ubuntu2) oneiric; urgency=low
1552
1553 * Remove langpack.mk; it no longer exists, and this package has no
1554
1555=== modified file 'debian/control'
1556--- debian/control 2010-01-29 16:22:17 +0000
1557+++ debian/control 2013-01-23 22:26:20 +0000
1558@@ -1,19 +1,16 @@
1559 Source: grokcore.component
1560 Section: python
1561 Priority: extra
1562-Build-Depends: cdbs (>= 0.4.43),
1563- debhelper (>= 6),
1564- python,
1565- python-central (>= 0.6.5),
1566+Build-Depends: debhelper (>= 7.0.50~),
1567+ python (>= 2.6.6-3~),
1568 python-setuptools (>= 0.6b3)
1569 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
1570 XSBC-Original-Maintainer: Łukasz Czyżykowski <lukasz.czyzykowski@canonical.com>
1571-Standards-Version: 3.8.4
1572+Standards-Version: 3.9.4
1573 XS-Python-Version: current
1574
1575 Package: python-grokcore.component
1576 Architecture: all
1577-XB-Python-Version: ${python:Versions}
1578 Depends:
1579 ${misc:Depends},
1580 ${python:Depends},
1581
1582=== added directory 'debian/patches'
1583=== added file 'debian/patches/series'
1584=== removed file 'debian/pycompat'
1585--- debian/pycompat 2010-01-29 16:22:17 +0000
1586+++ debian/pycompat 1970-01-01 00:00:00 +0000
1587@@ -1,1 +0,0 @@
1588-2
1589
1590=== modified file 'debian/rules'
1591--- debian/rules 2011-09-11 16:48:22 +0000
1592+++ debian/rules 2013-01-23 22:26:20 +0000
1593@@ -1,6 +1,3 @@
1594 #!/usr/bin/make -f
1595-
1596-DEB_PYTHON_SYSTEM := pycentral
1597-
1598-include /usr/share/cdbs/1/rules/debhelper.mk
1599-include /usr/share/cdbs/1/class/python-distutils.mk
1600+%:
1601+ dh $@ --with python2
1602
1603=== added directory 'debian/source'
1604=== added file 'debian/source/format'
1605--- debian/source/format 1970-01-01 00:00:00 +0000
1606+++ debian/source/format 2013-01-23 22:26:20 +0000
1607@@ -0,0 +1,1 @@
1608+3.0 (quilt)
1609
1610=== added file 'debian/watch'
1611--- debian/watch 1970-01-01 00:00:00 +0000
1612+++ debian/watch 2013-01-23 22:26:20 +0000
1613@@ -0,0 +1,2 @@
1614+version=3
1615+http://pypi.python.org/packages/source/g/grokcore.component/grokcore.component-(.+).tar.gz
1616
1617=== modified file 'setup.py'
1618--- setup.py 2010-01-29 16:22:17 +0000
1619+++ setup.py 2013-01-23 22:26:20 +0000
1620@@ -10,9 +10,13 @@
1621 read('CHANGES.txt')
1622 )
1623
1624+tests_require = [
1625+ 'zope.event',
1626+ ]
1627+
1628 setup(
1629 name='grokcore.component',
1630- version = '2.0',
1631+ version='2.5',
1632 author='Grok Team',
1633 author_email='grok-dev@zope.org',
1634 url='http://grok.zope.org',
1635@@ -32,11 +36,13 @@
1636 include_package_data=True,
1637 zip_safe=False,
1638 install_requires=['setuptools',
1639- 'martian >= 0.12',
1640+ 'martian >= 0.14',
1641 'zope.component',
1642 'zope.configuration',
1643 'zope.interface',
1644- 'zope.event',
1645+ # Note: zope.testing is NOT just a test dependency here.
1646 'zope.testing',
1647 ],
1648+ tests_require=tests_require,
1649+ extras_require={'test': tests_require},
1650 )
1651
1652=== modified file 'src/grokcore.component.egg-info/PKG-INFO'
1653--- src/grokcore.component.egg-info/PKG-INFO 2010-01-29 16:22:17 +0000
1654+++ src/grokcore.component.egg-info/PKG-INFO 2013-01-23 22:26:20 +0000
1655@@ -1,6 +1,6 @@
1656 Metadata-Version: 1.0
1657 Name: grokcore.component
1658-Version: 2.0
1659+Version: 2.5
1660 Summary: Grok-like configuration for basic components (adapters, utilities, subscribers)
1661 Home-page: http://grok.zope.org
1662 Author: Grok Team
1663@@ -29,34 +29,34 @@
1664 we need to make sure it's available to the ZCML machinery. We do this
1665 by including the meta configuration from ``grokcore.component``::
1666
1667- <include package="grokcore.component" file="meta.zcml" />
1668+ <include package="grokcore.component" file="meta.zcml" />
1669
1670 Put this line somewhere to the top of ``site.zcml``, next to other
1671 meta configuration includes. Now, further down the line, we can tell
1672 the machinery in ``grokcore.component`` to register all components in
1673 your package (let's say it's called ``helloworld``)::
1674
1675- <grok:grok package="helloworld" />
1676+ <grok:grok package="helloworld" />
1677
1678 To sum up, your ``site.zcml`` file should look like something like this::
1679
1680- <configure
1681- xmlns="http://namespaces.zope.org/zope"
1682- xmlns:grok="http://namespaces.zope.org/grok">
1683-
1684- <!-- do the meta configuration to make the ZCML directives available -->
1685- <include package="zope.foobar" file="meta.zcml" />
1686- <include package="zope.frobnaz" file="meta.zcml" />
1687- <include package="grokcore.component" file="meta.zcml" />
1688-
1689- <!-- now load the configuration of packages that we depend on -->
1690- <include package="zope.barfoo" />
1691- <include package="zope.somethingorother" />
1692-
1693- <!-- finally load my components which are based on grokcore.component -->
1694- <grok:grok package="helloworld" />
1695-
1696- </configure>
1697+ <configure
1698+ xmlns="http://namespaces.zope.org/zope"
1699+ xmlns:grok="http://namespaces.zope.org/grok">
1700+
1701+ <!-- do the meta configuration to make the ZCML directives available -->
1702+ <include package="zope.foobar" file="meta.zcml" />
1703+ <include package="zope.frobnaz" file="meta.zcml" />
1704+ <include package="grokcore.component" file="meta.zcml" />
1705+
1706+ <!-- now load the configuration of packages that we depend on -->
1707+ <include package="zope.barfoo" />
1708+ <include package="zope.somethingorother" />
1709+
1710+ <!-- finally load my components which are based on grokcore.component -->
1711+ <grok:grok package="helloworld" />
1712+
1713+ </configure>
1714
1715 Examples
1716 ========
1717@@ -67,26 +67,26 @@
1718 Here's a simple adapter that may be useful in Zope. It extracts the
1719 languages that a user prefers from the request::
1720
1721- import grokcore.component
1722- from zope.publisher.interfaces.browser import IBrowserRequest
1723- from zope.i18n.interfaces import IUserPreferredLanguages
1724-
1725- class CookieLanguage(grokcore.component.Adapter):
1726- """Extract the preferred language from a cookie"""
1727- grokcore.component.context(IBrowserRequest)
1728- grokcore.component.implements(IUserPreferredLanguages)
1729-
1730- # No need to implement __init__, it's already provided by the base class.
1731-
1732- def getPreferredLanguages(self):
1733- # This an adapter for the request, so self.context is the request.
1734- request = self.context
1735-
1736- # Extract the preferred language from a cookie:
1737- lang = request.cookies.get('language', 'en')
1738-
1739- # According to IUserPreferredLanguages, we must return a list.
1740- return [lang]
1741+ import grokcore.component
1742+ from zope.publisher.interfaces.browser import IBrowserRequest
1743+ from zope.i18n.interfaces import IUserPreferredLanguages
1744+
1745+ class CookieLanguage(grokcore.component.Adapter):
1746+ """Extract the preferred language from a cookie"""
1747+ grokcore.component.context(IBrowserRequest)
1748+ grokcore.component.implements(IUserPreferredLanguages)
1749+
1750+ # No need to implement __init__, it's already provided by the base class.
1751+
1752+ def getPreferredLanguages(self):
1753+ # This an adapter for the request, so self.context is the request.
1754+ request = self.context
1755+
1756+ # Extract the preferred language from a cookie:
1757+ lang = request.cookies.get('language', 'en')
1758+
1759+ # According to IUserPreferredLanguages, we must return a list.
1760+ return [lang]
1761
1762 Multi-adapter
1763 -------------
1764@@ -97,21 +97,24 @@
1765 the content object (model), the request and the view that they're
1766 supposed to be a part of::
1767
1768- import grokcore.component
1769- from zope.publisher.interfaces.browser import IBrowserRequest
1770- from zope.publisher.interfaces.browser import IBrowserPage
1771- from zope.contentprovider.interfaces import IContentProvider
1772-
1773- class HelloWorldProvider(grokcore.component.MultiAdapter):
1774- """Display Hello World!"""
1775- grokcore.component.adapts(Interface, IBrowserRequest, IBrowserPage)
1776- grokcore.component.implements(IContentProvider)
1777-
1778- def update(self):
1779- pass
1780-
1781- def render(self):
1782- return u'<p>Hello World!</p>'
1783+ import grokcore.component
1784+ from zope.publisher.interfaces.browser import IBrowserRequest
1785+ from zope.publisher.interfaces.browser import IBrowserPage
1786+ from zope.contentprovider.interfaces import IContentProvider
1787+
1788+ class HelloWorldProvider(grokcore.component.MultiAdapter):
1789+ """Display Hello World!"""
1790+ grokcore.component.adapts(Interface, IBrowserRequest, IBrowserPage)
1791+ grokcore.component.implements(IContentProvider)
1792+
1793+ def __init__(self, context, request, view):
1794+ pass
1795+
1796+ def update(self):
1797+ pass
1798+
1799+ def render(self):
1800+ return u'<p>Hello World!</p>'
1801
1802
1803 Global utility
1804@@ -122,24 +125,24 @@
1805 messages and is invoked when the i18n machinery needs to translate
1806 something::
1807
1808- import grokcore.component
1809- from zope.i18n.interfaces import ITranslationDomain
1810-
1811- class HelloWorldTranslationDomain(grokcore.component.GlobalUtility):
1812- grokcore.component.implements(ITranslationDomain)
1813- grokcore.component.name('helloworld')
1814-
1815- domain = u'helloworld'
1816-
1817- def translate(self, msgid, mapping=None, context=None,
1818- target_language=None, default=None):
1819- if target_language is None:
1820- preferred = IUserPreferredLanguages(context)
1821- target_language = preferred.getPreferredLanguages()[0]
1822-
1823- translations = {'de': u'Hallo Welt',
1824- 'nl': u'Hallo Wereld'}
1825- return translations.get(target_language, u'Hello World')
1826+ import grokcore.component
1827+ from zope.i18n.interfaces import ITranslationDomain
1828+
1829+ class HelloWorldTranslationDomain(grokcore.component.GlobalUtility):
1830+ grokcore.component.implements(ITranslationDomain)
1831+ grokcore.component.name('helloworld')
1832+
1833+ domain = u'helloworld'
1834+
1835+ def translate(self, msgid, mapping=None, context=None,
1836+ target_language=None, default=None):
1837+ if target_language is None:
1838+ preferred = IUserPreferredLanguages(context)
1839+ target_language = preferred.getPreferredLanguages()[0]
1840+
1841+ translations = {'de': u'Hallo Welt',
1842+ 'nl': u'Hallo Wereld'}
1843+ return translations.get(target_language, u'Hello World')
1844
1845 Of course, it's silly to implement your own translation domain utility
1846 if there are already implementations available in ``zope.i18n`` (one
1847@@ -147,18 +150,18 @@
1848 simple implementation for tests). Let's try to reuse that
1849 implementation and register an instance::
1850
1851- import grokcore.component
1852- from zope.i18n.interfaces import ITranslationDomain
1853- from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
1854-
1855- messages = {('de', u'Hello World'): u'Hallo Welt',
1856- ('nl', u'Hello World'): u'Hallo Wereld'}
1857- helloworld_domain = SimpleTranslationDomain(u'helloworld', messages)
1858-
1859- grokcore.component.global_utility(helloworld_domain,
1860- provides=ITranslationDomain,
1861- name='helloworld',
1862- direct=True)
1863+ import grokcore.component
1864+ from zope.i18n.interfaces import ITranslationDomain
1865+ from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
1866+
1867+ messages = {('de', u'Hello World'): u'Hallo Welt',
1868+ ('nl', u'Hello World'): u'Hallo Wereld'}
1869+ helloworld_domain = SimpleTranslationDomain(u'helloworld', messages)
1870+
1871+ grokcore.component.global_utility(helloworld_domain,
1872+ provides=ITranslationDomain,
1873+ name='helloworld',
1874+ direct=True)
1875
1876 Global adapter
1877 --------------
1878@@ -172,333 +175,265 @@
1879 example drawing on the ``z3c.form`` library, which provides an adapter factory
1880 factory for named widget attributes::
1881
1882- import zope.interface
1883- import zope.schema
1884- import grokcore.component
1885- import z3c.form.widget import ComputedWidgetAttribute
1886-
1887- class ISchema(Interface):
1888- """This schema will be used to power a z3c.form form"""
1889-
1890- field = zope.schema.TextLine(title=u"Sample field")
1891-
1892- ...
1893-
1894- label_override = z3c.form.widget.StaticWidgetAttribute(
1895- u"Override label", field=ISchema['field'])
1896-
1897- grokcore.component.global_adapter(label_override, name=u"label")
1898+ import zope.interface
1899+ import zope.schema
1900+ import grokcore.component
1901+ import z3c.form.widget import ComputedWidgetAttribute
1902+
1903+ class ISchema(Interface):
1904+ """This schema will be used to power a z3c.form form"""
1905+
1906+ field = zope.schema.TextLine(title=u"Sample field")
1907+
1908+ ...
1909+
1910+ label_override = z3c.form.widget.StaticWidgetAttribute(
1911+ u"Override label", field=ISchema['field'])
1912+
1913+ grokcore.component.global_adapter(label_override, name=u"label")
1914
1915 In the example above, the provided and adapted interfaces are deduced from the
1916 object returned by the ``StaticWidgetAttribute`` factory. The full syntax
1917 for global_adapter is::
1918
1919- global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
1920+ global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
1921
1922 The factory must be a callable (the adapter factory). Adapted interfaces are
1923 given as a tuple. You may use a single interface instead of a one-element
1924 tuple for single adapters. The provided interface is given as shown. The name
1925 defaults to u"" (an unnamed adapter).
1926
1927- Subscriber
1928- ----------
1929-
1930- Here we see a subscriber much like it occurs within Zope itself. It
1931- subscribes to the modified event for all annotatable objects (in other
1932- words, objects that can have metadata associated with them). When
1933- invoked, it updates the Dublin Core 'Modified' property accordingly::
1934-
1935- import datetime
1936- import grokcore.component
1937- from zope.annotation.interfaces import IAnnotatable
1938- from zope.lifecycleevent.interfaces import IObjectModifiedEvent
1939- from zope.dublincore.interfaces import IZopeDublinCore
1940-
1941- @grokcore.component.subscribe(IAnnotatable, IObjectModifiedEvent)
1942- def updateDublinCoreAfterModification(obj, event):
1943- """Updated the Dublin Core 'Modified' property when a modified
1944- event is sent for an object."""
1945- IZopeDublinCore(obj).modified = datetime.datetime.utcnow()
1946-
1947-
1948- API overview
1949- ============
1950-
1951- Base classes
1952- ------------
1953-
1954- ``Adapter``
1955- Base class for an adapter that adapts a single object (commonly
1956- referred to as the *context*). Use the ``context`` directive to
1957- specify which object to adapt and the ``implements`` directive to
1958- specify which interface the adapter will provide. If it's a named
1959- adapter, you may use the ``name`` directive to specify the name.
1960-
1961- ``MultiAdapter``
1962- Base class for an adapter that adapts *n* objects (where *n>=1*).
1963- Use the ``adapts`` directive to specify which kinds of objects are
1964- adapted and the ``implements`` directive to specify which
1965- interface the adapter will provide. If it's a named
1966- multi-adapter, you may use the ``name`` directive to specify the
1967- name.
1968-
1969- ``GlobalUtility``
1970- Base class for a globally registered utility. Unless you use the
1971- ``direct`` directive to indicate that the class itself should be
1972- registered as a utility, the class will automatically be
1973- instantiated, therefore the constructor may not take any
1974- arguments. Use the ``implements`` directive to specify which
1975- interface the utility provides, or if that is not unambiguous,
1976- also use the ``provides`` directive to specify which of the
1977- implemented interfaces should be used when registering the
1978- utility. If it's a named utility, you may use the ``name``
1979- directive to specify the name.
1980-
1981- ``Context``
1982- Subclasses of this will automatically be found as potential
1983- contexts for adapters and other types of context-dependent
1984- components.
1985-
1986-
1987- Class-level directives
1988- ----------------------
1989-
1990- ``implements(iface1, iface2, ...)``
1991- declares that a class implements the interfaces ``iface1``,
1992- ``iface2``, etc. It is identical to
1993- ``zope.interface.implements``.
1994-
1995- ``implementsOnly(iface1, iface2, ...)``
1996- declares that a class *only* implements the interfaces ``iface1``,
1997- ``iface2``, etc. It is identical to
1998- ``zope.interface.implementsOnly``.
1999-
2000- ``classProvides(iface1, iface2, ...)``
2001- declares that a class object (as opposed to instances of the class)
2002- provides the interfaces ``iface1``, ``iface2``, etc. It is identical to
2003- ``zope.interface.classProvides``.
2004-
2005- ``context(iface_or_class)``
2006- declares the type of object that the adapter (or a similar
2007- context-dependent component) adapts. This can either be an
2008- interface (in this case all objects providing this interface will
2009- be eligible contexts for the adapter) or a class (then only
2010- instances of that particular class are eligible).
2011-
2012- ``adapts(iface_or_class1, iface_or_class_2, ...)``
2013- declares the types of objects that a multi-adapter adapts.
2014-
2015- ``name(ascii_or_unicode)``
2016- declares the name of a named utility, named adapter, etc.
2017-
2018- ``title(ascii_or_unicode)``
2019- declares the human-readable title of a component (such as a
2020- permission, role, etc.)
2021-
2022- ``provides(iface)``
2023- declares the interface that a utility provides (as opposed to
2024- potentially multiple interfaces that the class implements).
2025-
2026- ``direct()``
2027- declares that a ``GlobalUtility`` class should be registered as a
2028- utility itself, rather than an instance of it.
2029-
2030- ``baseclass()``
2031- declares that a subclass of an otherwise automatically configured
2032- component should not be registered, and that it serves as a base
2033- class instead.
2034-
2035-
2036- Module-level directives
2037- -----------------------
2038-
2039- ``global_utility(class, [provides=iface, name=ascii_or_unicode, direct=bool])``
2040- registers an instance of ``class`` (or ``class`` itself, depending
2041- on the value of the ``direct`` parameter) as a global utility.
2042- This allows you to register global utilities that don't inherit
2043- from the ``GlobalUtility`` base class.
2044-
2045- ``global_adapter(factory, [adapts=tuple_of_interfaces, provides=iface, name=ascii_or_unicode])``
2046- registers the ``factory`` callable as a global adapter. The ``adapts``
2047- argument may be a tuple of interfaces or a single interface, if this is
2048- a single adapter. Both ``adapts`` and ``provides`` will be deduced from
2049- information annotated onto the factory if necessary. If no adapted
2050- interface can be determined, the current context will be assumed. The
2051- name defaults to u"". This allows you to register global adapters that
2052- don't inherit from the ``Adapter`` or ``MultiAdapter`` base classes.
2053-
2054- Function decorators
2055- -------------------
2056-
2057- ``@adapter(iface_or_class1, iface_or_class2, ..., name=u"name")``
2058- registers the function as an adapter for the specific interface. The
2059- ``name`` argument must be a keyword argument and is optional. If given,
2060- a named adapter is registered.
2061-
2062- ``@implementer(iface1, iface2, ...)```
2063- declares that the function implements a certain interface (or a
2064- number of interfaces). This is useful when a function serves as an object
2065- factory, e.g. as an adapter.
2066-
2067- ``@provider(iface1, iface2, ...)```
2068- declares that the function object provides a certain interface (or a
2069- number of interfaces). This is akin to calling directlyProvides() on
2070- the function object.
2071-
2072- ``@subscribe(iface_or_class1, iface_or_class2, ...)``
2073- declares that a function is to be registered as an event handler
2074- for the specified objects. Normally, an event handler is simply
2075- registered as a subscriber for the event interface. In case of
2076- object events, the event handler is registered as a subscriber for
2077- the object type and the event interface.
2078+ Handling events
2079+ ---------------
2080+
2081+ Here we see an event handler much like it occurs within Zope itself. It
2082+ subscribes to the modified event for all annotatable objects (in other words,
2083+ objects that can have metadata associated with them). When invoked, it updates
2084+ the Dublin Core 'Modified' property accordingly::
2085+
2086+ import datetime
2087+ import grokcore.component
2088+ from zope.annotation.interfaces import IAnnotatable
2089+ from zope.lifecycleevent.interfaces import IObjectModifiedEvent
2090+ from zope.dublincore.interfaces import IZopeDublinCore
2091+
2092+ @grokcore.component.subscribe(IAnnotatable, IObjectModifiedEvent)
2093+ def updateDublinCoreAfterModification(obj, event):
2094+ """Updated the Dublin Core 'Modified' property when a modified
2095+ event is sent for an object."""
2096+ IZopeDublinCore(obj).modified = datetime.datetime.utcnow()
2097+
2098+ Subscriptions
2099+ -------------
2100+
2101+ Subscriptions look similar to Adapter, however, unlike regular adapters,
2102+ subscription adapters are used when we want all of the adapters that adapt an
2103+ object to a particular adapter.
2104+
2105+ Analogous to MultiAdapter, there is a MultiSubscription component that "adapts"
2106+ multiple objects.
2107
2108 Changes
2109 =======
2110
2111+ 2.5 (2012-05-01)
2112+ ----------------
2113+
2114+ - Introduce provideUtility, providerAdapter, provideSubscriptionAdapter,
2115+ provideHandler and provideInterface in grokcore.component. These by default
2116+ delegate the registration of components to the global site manager like
2117+ was done before, but provide the possibility for custom registries for the
2118+ grokked components.
2119+
2120+ - Fix the `global_adapter` to properly use information annotated by
2121+ ``grok.adapter``, and using the IContext object if it was not
2122+ specified. (Fix Launchpad issue #960097).
2123+
2124+ - Add a ``key`` option to ``sort_components`` that behave like ``key``
2125+ options available on standard Python sort methods.
2126+
2127+ 2.4 (2011-04-27)
2128+ ----------------
2129+
2130+ - Fix the `global_adapter` directive implementation to accept an explicit
2131+ "empty" name for nameless adapter registrations (as it used to be that
2132+ providing an empty name in the registration would actually result in
2133+ registering a named adapter in case the factory has a `grok.name`).
2134+
2135+ 2.3 (2011-02-14)
2136+ ----------------
2137+
2138+ - Implement the generic (Multi)Subscriptions components.
2139+
2140+ 2.2 (2010-11-03)
2141+ ----------------
2142+
2143+ - The default values computation for the context directive and the provides
2144+ directive is now defined in the directives themselves. This means that where
2145+ the values for these directives is being retrieved, the "default_context"
2146+ function does not need to be passed along anymore for general cases.
2147+
2148+ Analogous to this, when getting values for the provides directive the
2149+ "default_provides" function does not need to be passed along in the general
2150+ case.
2151+
2152+ 2.1 (2010-11-01)
2153+ ----------------
2154+
2155+ * Made package comply to zope.org repository policy.
2156+
2157+ * Moved directives 'order' from grokcore.viewlet and 'path' from
2158+ grokcore.view to this very package.
2159+
2160+ * Tiny dependency adjustment: moved zope.event to test dependencies.
2161+
2162+ * Port from 1.x branch exclude parameter to the Grok ZCML directive.
2163+
2164+ * Port from 1.x branch the ignore of testing.py modules.
2165+
2166 2.0 (2009-09-16)
2167 ----------------
2168
2169 * Use a newer version of Martian that has better support for
2170- inheritance. This is demonstrated in ``tests/inherit``.
2171+ inheritance. This is demonstrated in ``tests/inherit``.
2172
2173 * The ``ContextGrokker`` and the ``scan.py`` module have gone away
2174- thanks the newer Martian.
2175+ thanks the newer Martian.
2176
2177 * Directive implementations (in their factory method) should *not*
2178- bind directives. Directive binding cannot take place at import time,
2179- but only at grok time. Binding directives during import time (when
2180- directives are executed) can lead to change problems. (we noticed
2181- this during our refactoring to use the new Martian).
2182+ bind directives. Directive binding cannot take place at import time,
2183+ but only at grok time. Binding directives during import time (when
2184+ directives are executed) can lead to change problems. (we noticed
2185+ this during our refactoring to use the new Martian).
2186
2187 * Use 1.0b1 versions.cfg in Grok's release info instead of a local
2188- copy; a local copy for all grokcore packages is just too hard to
2189- maintain.
2190+ copy; a local copy for all grokcore packages is just too hard to
2191+ maintain.
2192
2193 1.7 (2009-06-01)
2194 ----------------
2195
2196 * Add missing provider, global_adapter, implementsOnly, classProvides() to
2197- the module interface so that they are included in __all__
2198-
2199+ the module interface so that they are included in __all__
2200
2201 1.6 (2009-04-10)
2202 ----------------
2203
2204 * Add convenience imports for implementsOnly() and classProvides() class
2205- declarations form zope.interface.
2206+ declarations form zope.interface.
2207
2208 * Add support for registering global adapters at module level::
2209
2210- grok.global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
2211+ grok.global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")
2212
2213- Only 'factory' is required. If only a single interface is adapted, the
2214- second argument may be a single interface instead of a tuple. If the
2215- component has declared adapted/provided interfaces, the second and third
2216- arguments may be omitted.
2217+ Only 'factory' is required. If only a single interface is adapted, the
2218+ second argument may be a single interface instead of a tuple. If the
2219+ component has declared adapted/provided interfaces, the second and third
2220+ arguments may be omitted.
2221
2222 * Add support for an @provider decorator to let a function directly provide
2223- an interface::
2224-
2225- @grok.provider(IFoo, IBar)
2226- def some_function():
2227- ...
2228-
2229- This is equivalent to doing alsoProvides(some_function, IFoo, IBar).
2230+ an interface::
2231+
2232+ @grok.provider(IFoo, IBar)
2233+ def some_function():
2234+ ...
2235+
2236+ This is equivalent to doing alsoProvides(some_function, IFoo, IBar).
2237
2238 * Add support for named adapters with the @adapter decorator::
2239
2240- @grok.adapter(IAdaptedOne, IAdaptedTwo, name=u"foo")
2241- def some_function(one, two):
2242- ...
2243+ @grok.adapter(IAdaptedOne, IAdaptedTwo, name=u"foo")
2244+ def some_function(one, two):
2245+ ...
2246
2247 1.5.1 (2008-07-28)
2248 ------------------
2249
2250 * The ``IGrokcoreComponentAPI`` interface was missing declarations for
2251- the ``title`` and ``description`` directives.
2252+ the ``title`` and ``description`` directives.
2253
2254 1.5 (2008-07-22)
2255 ----------------
2256
2257 * Fix https://bugs.launchpad.net/grok/+bug/242353: grokcore.component
2258- contains old-style test setup. There is no `register_all_tests`
2259- method in grokcore.component.testing anymore. Use z3c.testsetup
2260- instead.
2261+ contains old-style test setup. There is no `register_all_tests`
2262+ method in grokcore.component.testing anymore. Use z3c.testsetup
2263+ instead.
2264
2265 * Allow functions that have been marked with @grok.subscribe also be
2266- registered with ``zope.component.provideHandler()`` manually. This
2267- is useful for unit tests where you may not want to grok a whole
2268- module.
2269+ registered with ``zope.component.provideHandler()`` manually. This
2270+ is useful for unit tests where you may not want to grok a whole
2271+ module.
2272
2273 * Document grokcore.component's public API in an interface,
2274- ``IGrokcoreComponentAPI``. When you now do::
2275-
2276- from grokcore.component import *
2277-
2278- only the items documented in that interface will be imported into
2279- your local namespace.
2280+ ``IGrokcoreComponentAPI``. When you now do::
2281+
2282+ from grokcore.component import *
2283+
2284+ only the items documented in that interface will be imported into
2285+ your local namespace.
2286
2287 1.4 (2008-06-11)
2288 ----------------
2289
2290 * Ported class grokkers to make use of further improvements in Martian.
2291- This requires Martian 0.10.
2292+ This requires Martian 0.10.
2293
2294 1.3 (2008-05-14)
2295 ----------------
2296
2297 * Ported class grokkers to make use of the new declarative way of
2298- retrieving directive information from a class. This requires
2299- Martian 0.9.6.
2300+ retrieving directive information from a class. This requires
2301+ Martian 0.9.6.
2302
2303 1.2.1 (2008-05-04)
2304 ------------------
2305
2306 * Upgrade to Martian 0.9.5, which has a slight change in the signature of
2307- ``scan_for_classes``.
2308+ ``scan_for_classes``.
2309
2310 * Remove an unnecessary import ``methods_from_class`` from
2311- ``grokcore.component.scan``.
2312+ ``grokcore.component.scan``.
2313
2314 1.2 (2008-05-04)
2315 ----------------
2316
2317 * Ported directives to Martian's new directive implementation. As a
2318- result, nearly all helper functions that were available from
2319- ``grokcore.component.util`` have been removed. The functionality is
2320- mostly available from the directives themselves now.
2321+ result, nearly all helper functions that were available from
2322+ ``grokcore.component.util`` have been removed. The functionality is
2323+ mostly available from the directives themselves now.
2324
2325 * The ``baseclass`` directive has been moved to Martian.
2326
2327 * The ``order`` directive and its helper functions have been moved
2328- back to Grok, as it was of no general use, but very specific to
2329- viewlets.
2330+ back to Grok, as it was of no general use, but very specific to
2331+ viewlets.
2332
2333 1.1 (2008-05-03)
2334 ----------------
2335
2336 * ``determine_module_component`` now looks for classes that implement
2337- a certain interface (such as ``IContext``), instead of taking a list
2338- of classes. If looking for ``IContext``, it still will find
2339- ``Context`` subclasses, as these were also made to implement
2340- ``IContext``.
2341+ a certain interface (such as ``IContext``), instead of taking a list
2342+ of classes. If looking for ``IContext``, it still will find
2343+ ``Context`` subclasses, as these were also made to implement
2344+ ``IContext``.
2345
2346 * Move the ``public_methods_from_class`` helper function back to Grok,
2347- it isn't used at all in ``grokcore.component``.
2348+ it isn't used at all in ``grokcore.component``.
2349
2350 1.0.1 (2008-05-02)
2351 ------------------
2352
2353 * The grokkers for adapters and global utilities did not use the
2354- correct value for the *provided* interface in the configuration
2355- action discriminator. Because of this, uninformative and
2356- potentially wrong conflict errors would occur, as well as no
2357- conflict where a conflict should have occurred.
2358+ correct value for the *provided* interface in the configuration
2359+ action discriminator. Because of this, uninformative and
2360+ potentially wrong conflict errors would occur, as well as no
2361+ conflict where a conflict should have occurred.
2362
2363 * The grokker for the ``global_utility()`` directive did immediate
2364- registrations instead of generating configuration actions.
2365- Therefore it did not provoke ``ConflictErrors`` for conflicting
2366- registrations.
2367+ registrations instead of generating configuration actions.
2368+ Therefore it did not provoke ``ConflictErrors`` for conflicting
2369+ registrations.
2370
2371 * Improved documentation
2372
2373@@ -506,8 +441,8 @@
2374 ----------------
2375
2376 * Created ``grokcore.component`` in March 2008 by factoring basic
2377- component base classes and their directives and grokkers out of
2378- Grok.
2379+ component base classes and their directives and grokkers out of
2380+ Grok.
2381
2382 Platform: UNKNOWN
2383 Classifier: Intended Audience :: Developers
2384
2385=== modified file 'src/grokcore.component.egg-info/SOURCES.txt'
2386--- src/grokcore.component.egg-info/SOURCES.txt 2010-01-29 16:22:17 +0000
2387+++ src/grokcore.component.egg-info/SOURCES.txt 2013-01-23 22:26:20 +0000
2388@@ -5,11 +5,9 @@
2389 LICENSE.txt
2390 README.txt
2391 TODO.txt
2392+bootstrap.py
2393 buildout.cfg
2394-setup.cfg
2395 setup.py
2396-versions.cfg
2397-bootstrap/bootstrap.py
2398 src/grokcore/__init__.py
2399 src/grokcore.component.egg-info/PKG-INFO
2400 src/grokcore.component.egg-info/SOURCES.txt
2401@@ -25,7 +23,9 @@
2402 src/grokcore/component/interfaces.py
2403 src/grokcore/component/meta.py
2404 src/grokcore/component/meta.zcml
2405+src/grokcore/component/subscription.py
2406 src/grokcore/component/testing.py
2407+src/grokcore/component/util.py
2408 src/grokcore/component/zcml.py
2409 src/grokcore/component/templates/default_display_form.pt
2410 src/grokcore/component/templates/default_edit_form.pt
2411@@ -89,6 +89,24 @@
2412 src/grokcore/component/tests/inherit/__init__.py
2413 src/grokcore/component/tests/inherit/inherit.py
2414 src/grokcore/component/tests/inherit/inherit_fixture.py
2415+src/grokcore/component/tests/order/__init__.py
2416+src/grokcore/component/tests/order/arg_orderdirective.py
2417+src/grokcore/component/tests/order/combined_orderdirective.py
2418+src/grokcore/component/tests/order/combinednoorder_orderdirective.py
2419+src/grokcore/component/tests/order/inter1.py
2420+src/grokcore/component/tests/order/inter2.py
2421+src/grokcore/component/tests/order/noarg_orderdirective.py
2422+src/grokcore/component/tests/order/nodirective.py
2423+src/grokcore/component/tests/subscriptions/__init__.py
2424+src/grokcore/component/tests/subscriptions/decorator.py
2425+src/grokcore/component/tests/subscriptions/multisubscriptions.py
2426+src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py
2427+src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py
2428+src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py
2429+src/grokcore/component/tests/subscriptions/ordered_subscriptions.py
2430+src/grokcore/component/tests/subscriptions/subscriptions.py
2431+src/grokcore/component/tests/subscriptions/subscriptions_no_context.py
2432+src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py
2433 src/grokcore/component/tests/utility/__init__.py
2434 src/grokcore/component/tests/utility/conflict.py
2435 src/grokcore/component/tests/utility/implementsmany.py
2436
2437=== modified file 'src/grokcore.component.egg-info/requires.txt'
2438--- src/grokcore.component.egg-info/requires.txt 2010-01-29 16:22:17 +0000
2439+++ src/grokcore.component.egg-info/requires.txt 2013-01-23 22:26:20 +0000
2440@@ -1,7 +1,9 @@
2441 setuptools
2442-martian >= 0.12
2443+martian >= 0.14
2444 zope.component
2445 zope.configuration
2446 zope.interface
2447-zope.event
2448-zope.testing
2449\ No newline at end of file
2450+zope.testing
2451+
2452+[test]
2453+zope.event
2454\ No newline at end of file
2455
2456=== modified file 'src/grokcore/component/__init__.py'
2457--- src/grokcore/component/__init__.py 2010-01-29 16:22:17 +0000
2458+++ src/grokcore/component/__init__.py 2013-01-23 22:26:20 +0000
2459@@ -1,6 +1,6 @@
2460 ##############################################################################
2461 #
2462-# Copyright (c) 2006-2007 Zope Corporation and Contributors.
2463+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
2464 # All Rights Reserved.
2465 #
2466 # This software is subject to the provisions of the Zope Public License,
2467@@ -14,17 +14,60 @@
2468 """Grok
2469 """
2470
2471+from zope.component import adapts
2472+adapts.__doc__ = "Declares the types of objects that a multi-adapter adapts."
2473+
2474 from zope.interface import implements, implementsOnly, classProvides
2475-from zope.component import adapts
2476
2477+from martian import baseclass
2478+from martian.error import GrokError, GrokImportError
2479 from martian import ClassGrokker, InstanceGrokker, GlobalGrokker
2480-from grokcore.component.components import Adapter, GlobalUtility, MultiAdapter, Context
2481-
2482-from martian import baseclass
2483+
2484+from grokcore.component.components import (
2485+ Adapter,
2486+ Context,
2487+ GlobalUtility,
2488+ MultiAdapter,
2489+ MultiSubscription,
2490+ Subscription,
2491+ )
2492+
2493 from grokcore.component.directive import (
2494- context, name, title, description, provides, global_utility, global_adapter, direct)
2495-from grokcore.component.decorators import subscribe, adapter, implementer, provider
2496-from martian.error import GrokError, GrokImportError
2497+ context,
2498+ description,
2499+ direct,
2500+ global_adapter,
2501+ global_utility,
2502+ name,
2503+ order,
2504+ path,
2505+ provides,
2506+ title,
2507+ )
2508+
2509+from grokcore.component.decorators import (
2510+ adapter,
2511+ implementer,
2512+ provider,
2513+ subscribe,
2514+ )
2515+
2516+from grokcore.component.subscription import (
2517+ queryMultiSubscriptions,
2518+ queryOrderedMultiSubscriptions,
2519+ queryOrderedSubscriptions,
2520+ querySubscriptions,
2521+ )
2522+
2523+from grokcore.component.util import (
2524+ getSiteManager,
2525+ provideAdapter,
2526+ provideHandler,
2527+ provideInterface,
2528+ provideSubscriptionAdapter,
2529+ provideUtility,
2530+ sort_components,
2531+ )
2532
2533 # Import this module so that it's available as soon as you import the
2534 # 'grokcore.component' package. Useful for tests and interpreter examples.
2535
2536=== modified file 'src/grokcore/component/components.py'
2537--- src/grokcore/component/components.py 2010-01-29 16:22:17 +0000
2538+++ src/grokcore/component/components.py 2013-01-23 22:26:20 +0000
2539@@ -1,6 +1,6 @@
2540 ##############################################################################
2541 #
2542-# Copyright (c) 2006-2007 Zope Corporation and Contributors.
2543+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
2544 # All Rights Reserved.
2545 #
2546 # This software is subject to the provisions of the Zope Public License,
2547@@ -17,15 +17,96 @@
2548
2549 from grokcore.component.interfaces import IContext
2550
2551+
2552 class Adapter(object):
2553+ """Base class for an adapter that adapts a single object (commonly referred
2554+ to as the *context*).
2555+
2556+ Use the ``context`` directive to specify which object to adapt and the
2557+ ``implements`` directive to specify which interface the adapter will
2558+ provide. If it's a named adapter, you may use the ``name`` directive to
2559+ specify the name.
2560+
2561+ .. attribute:: context
2562+
2563+ The adapted object.
2564+
2565+ """
2566+
2567 def __init__(self, context):
2568 self.context = context
2569
2570+
2571+class MultiAdapter(object):
2572+ """Base class for an adapter that adapts *n* objects (where *n>=1*).
2573+
2574+ Use the ``adapts`` directive to specify which kinds of objects are adapted
2575+ and the ``implements`` directive to specify which interface the adapter
2576+ will provide. If it's a named multi-adapter, you may use the ``name``
2577+ directive to specify the name.
2578+
2579+ Note that contrary to the Adapter, the MultiAdapter base class does not
2580+ provide an `__init__` method. An `__init__` needs to accept the same number
2581+ of arguments as are used in the `adapts` directive.
2582+
2583+ """
2584+ pass
2585+
2586+
2587 class GlobalUtility(object):
2588- pass
2589-
2590-class MultiAdapter(object):
2591- pass
2592+ """Base class to define a globally registered utility.
2593+
2594+ Base class for a globally registered utility. Unless you use the ``direct``
2595+ directive to indicate that the class itself should be registered as a
2596+ utility, the class will automatically be instantiated, therefore the
2597+ constructor may not take any arguments. Use the ``implements`` directive to
2598+ specify which interface the utility provides, or if that is not
2599+ unambiguous, also use the ``provides`` directive to specify which of the
2600+ implemented interfaces should be used when registering the utility. If it's
2601+ a named utility, you may use the ``name`` directive to specify the name.
2602+
2603+ """
2604+ pass
2605+
2606+
2607+class Subscription(object):
2608+ """Base class for a subscription adapter.
2609+
2610+ Subscriptions are similar to adapters, except that it is possible to
2611+ register multiple unnamed subscriptions for identical ``context`` and
2612+ ``provides``.
2613+
2614+ Use the ``context`` directive to explicitly set the interface to adapt
2615+ from. When omitted the current context is assumed. Use the ``implements``
2616+ directive to specify which interface the subscription provides, or if that
2617+ is not unambiguous, also use the ``provides`` directive to specify which of
2618+ the implemented interfaces should be used when registering the subscription.
2619+
2620+ """
2621+
2622+ def __init__(self, context):
2623+ self.context = context
2624+
2625+
2626+class MultiSubscription(object):
2627+ """Base class for a subscription multi-adapter.
2628+
2629+ MultiSubscriptions are similar to multi adapters, except that it is
2630+ possible to register multiple unnamed subscriptions for identical
2631+ ``adapts`` and ``provides``.
2632+
2633+ Use the ``adapts`` directive to explicitly set the multiple interfaces to
2634+ adapt from. Use the ``implements`` directive to specify which interface the
2635+ subscription provides, or if that is not unambiguous, also use the
2636+ ``provides`` directive to specify which of the implemented interfaces
2637+ should be used when registering the multi subscription.
2638+
2639+ """
2640+
2641
2642 class Context(object):
2643+ """Subclasses of this will automatically be found as potential contexts for
2644+ adapters and other types of context-dependent components.
2645+
2646+ """
2647 implements(IContext)
2648
2649=== modified file 'src/grokcore/component/decorators.py'
2650--- src/grokcore/component/decorators.py 2010-01-29 16:22:17 +0000
2651+++ src/grokcore/component/decorators.py 2013-01-23 22:26:20 +0000
2652@@ -1,6 +1,6 @@
2653 ##############################################################################
2654 #
2655-# Copyright (c) 2006 Zope Corporation and Contributors.
2656+# Copyright (c) 2006 Zope Foundation and Contributors.
2657 # All Rights Reserved.
2658 #
2659 # This software is subject to the provisions of the Zope Public License,
2660@@ -23,7 +23,14 @@
2661 from zope.interface.declarations import DescriptorAwareMetaClasses
2662
2663 class subscribe:
2664-
2665+ """Declares that a function is to be registered as an event handler for the
2666+ specified objects.
2667+
2668+ Normally, an event handler is simply registered as a subscriber for the
2669+ event interface. In case of object events, the event handler is registered
2670+ as a subscriber for the object type and the event interface.
2671+
2672+ """
2673 def __init__(self, *args):
2674 self.subscribed = args
2675
2676@@ -37,17 +44,25 @@
2677 raise GrokImportError("@grok.subscribe requires at least one "
2678 "argument.")
2679
2680+ # Add the function and subscribed interfaces to the
2681+ # grok.subscribers module annotation.
2682 subscribers = frame.f_locals.get('__grok_subscribers__', None)
2683 if subscribers is None:
2684 frame.f_locals['__grok_subscribers__'] = subscribers = []
2685 subscribers.append((function, self.subscribed))
2686
2687- # Also add __grok_adapts__ attribute to the function so that
2688- # you can manually register the subscriber with, say,
2689- # provideHandler.
2690+ # Also store the subscribed interfaces on the
2691+ # attribute__component_adapts__ for provideHandler to register
2692+ # the subscriber (in case you don't grok your package and
2693+ # register it manually)
2694 return zope.component.adapter(*self.subscribed)(function)
2695
2696 class adapter(zope.component.adapter):
2697+ """Registers the function as an adapter for the specific interface.
2698+
2699+ The ``name`` argument must be a keyword argument and is optional. If given,
2700+ a named adapter is registered.
2701+ """
2702
2703 # Override the z.c.adapter decorator to force sanity checking and
2704 # have better error reporting and add the ability to capture the name
2705@@ -59,18 +74,18 @@
2706 if type(interfaces[0]) is types.FunctionType:
2707 raise GrokImportError(
2708 "@grok.adapter requires at least one argument.")
2709-
2710+
2711 self.name = u""
2712-
2713+
2714 if kw:
2715 if 'name' in kw:
2716 self.name = kw.pop('name')
2717 if kw:
2718 raise GrokImportError(
2719 "@grok.adapter got unexpected keyword arguments: %s" % ','.join(kw.keys()))
2720-
2721+
2722 zope.component.adapter.__init__(self, *interfaces)
2723-
2724+
2725 def __call__(self, ob):
2726 ob = zope.component.adapter.__call__(self, ob)
2727 if self.name:
2728@@ -78,6 +93,13 @@
2729 return ob
2730
2731 class implementer(zope.interface.implementer):
2732+ """Declares that the function implements a certain interface (or a number
2733+ of interfaces).
2734+
2735+ This is useful when a function serves as an object factory, e.g. as an
2736+ adapter.
2737+
2738+ """
2739
2740 def __call__(self, ob):
2741 # XXX we do not have function grokkers (yet) so we put the annotation
2742@@ -87,10 +109,16 @@
2743 if adapters is None:
2744 frame.f_locals['__grok_adapters__'] = adapters = []
2745 adapters.append(ob)
2746+
2747 return zope.interface.implementer.__call__(self, ob)
2748
2749 class provider:
2750-
2751+ """Declares that the function object provides a certain interface (or a
2752+ number of interfaces).
2753+
2754+ This is akin to calling directlyProvides() on the function object.
2755+
2756+ """
2757 def __init__(self, *interfaces):
2758 self.interfaces = interfaces
2759
2760
2761=== modified file 'src/grokcore/component/directive.py'
2762--- src/grokcore/component/directive.py 2010-01-29 16:22:17 +0000
2763+++ src/grokcore/component/directive.py 2013-01-23 22:26:20 +0000
2764@@ -1,6 +1,6 @@
2765 ##############################################################################
2766 #
2767-# Copyright (c) 2006-2007 Zope Corporation and Contributors.
2768+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
2769 # All Rights Reserved.
2770 #
2771 # This software is subject to the provisions of the Zope Public License,
2772@@ -14,11 +14,28 @@
2773 """Grok directives.
2774 """
2775 import martian
2776-import grokcore.component
2777+import martian.util
2778+from martian.error import GrokError, GrokImportError
2779+from martian.util import scan_for_classes
2780+from zope import interface
2781 from zope.interface.interfaces import IInterface
2782-from martian.error import GrokImportError
2783+from grokcore.component.interfaces import IContext
2784
2785 class global_utility(martian.MultipleTimesDirective):
2786+ """Registers an instance of ``class`` (or ``class`` itself, depending on
2787+ the value of the ``direct`` parameter) as a global utility.
2788+
2789+ This allows you to register global utilities that don't inherit from the
2790+ ``GlobalUtility`` base class.
2791+
2792+ :param class: The class to register as a global utility.
2793+ :param provides: Optionally, the interface the utility will provide.
2794+ :param name: Optionally, a name for a named utility registration.
2795+ :type name: string or unicode
2796+ :param direct: Optionally, a flag indicating the class directly provides
2797+ the interfaces, and it needs not to be instantiated.
2798+ :type direct: boolean
2799+ """
2800 scope = martian.MODULE
2801
2802 def factory(self, factory, provides=None, name=u'', direct=False):
2803@@ -29,14 +46,34 @@
2804 return (factory, provides, name, direct)
2805
2806 class global_adapter(martian.MultipleTimesDirective):
2807+ """Registers the ``factory`` callable as a global adapter.
2808+
2809+ This allows you to register global adapters that
2810+ don't inherit from the ``Adapter`` or ``MultiAdapter`` base classes.
2811+
2812+ :param factory: The class that implements the adaptation.
2813+ :param adapts: Optionally, a single interface or a tuple of multiple
2814+ interfaces to adapts from. If omitted, this information is
2815+ deduced from the annotation on the factory. If no adapted
2816+ interface can be determined the current context will be
2817+ assumed.
2818+ :param provides: Optionally, the interface the adapter will provide. If
2819+ omitted, this information is deduced from the annotations
2820+ on the factory.
2821+ :param name: Optionally, a name for a named adapter registration.
2822+ :type name: string or unicode
2823+
2824+ """
2825 scope = martian.MODULE
2826
2827- def factory(self, factory, adapts=None, provides=None, name=u''):
2828+ def factory(self, factory, adapts=None, provides=None, name=None):
2829 if provides is not None and not IInterface.providedBy(provides):
2830 raise GrokImportError(
2831 "You can only pass an interface to the "
2832 "provides argument of %s." % self.name)
2833- if not isinstance(adapts, (list, tuple,)):
2834+ if adapts is None:
2835+ adapts = getattr(factory, '__component_adapts__', None)
2836+ elif not isinstance(adapts, (list, tuple,)):
2837 adapts = (adapts,)
2838 elif isinstance(adapts, list):
2839 adapts = tuple(adapts)
2840@@ -44,17 +81,49 @@
2841 return (factory, adapts, provides, name)
2842
2843 class name(martian.Directive):
2844+ """Declares the name of a named utility, named adapter, etc.
2845+
2846+ """
2847 scope = martian.CLASS
2848 store = martian.ONCE
2849+ validate = martian.validateText
2850 default = u''
2851- validate = martian.validateText
2852
2853 class context(martian.Directive):
2854+ """Declares the type of object that the adapter (or a similar context-
2855+ dependent component) adapts.
2856+
2857+ :param context: Interface (in this case all objects providing this
2858+ interface will be eligible contexts for the adaptation) or
2859+ a class (then only instances of that particular class are
2860+ eligible).
2861+ """
2862+
2863 scope = martian.CLASS_OR_MODULE
2864 store = martian.ONCE
2865 validate = martian.validateInterfaceOrClass
2866
2867+ @classmethod
2868+ def get_default(cls, component, module=None, **data):
2869+ components = list(scan_for_classes(module, IContext))
2870+ if len(components) == 0:
2871+ raise GrokError(
2872+ "No module-level context for %r, please use the 'context' "
2873+ "directive." % (component), component)
2874+ elif len(components) == 1:
2875+ component = components[0]
2876+ else:
2877+ raise GrokError(
2878+ "Multiple possible contexts for %r, please use the 'context' "
2879+ "directive."
2880+ % (component), component)
2881+ return component
2882+
2883 class title(martian.Directive):
2884+ """Declares the human-readable title of a component (such as a permission,
2885+ role, etc.)
2886+
2887+ """
2888 scope = martian.CLASS
2889 store = martian.ONCE
2890 validate = martian.validateText
2891@@ -63,9 +132,41 @@
2892 pass
2893
2894 class direct(martian.MarkerDirective):
2895- scope = martian.CLASS
2896+ """Declares that a ``GlobalUtility`` class should be registered as a
2897+ utility itself, rather than an instance of it.
2898+
2899+ """
2900+ scope = martian.CLASS
2901+
2902+class order(martian.Directive):
2903+ scope = martian.CLASS
2904+ store = martian.ONCE
2905+ default = 0, 0
2906+
2907+ _order = 0
2908+
2909+ def factory(self, value=0):
2910+ order._order += 1
2911+ return value, order._order
2912+
2913+class path(martian.Directive):
2914+ scope = martian.CLASS
2915+ store = martian.ONCE
2916+ validate = martian.validateText
2917
2918 class provides(martian.Directive):
2919+ """Declares the interface that a adapter or utility provides for the
2920+ registration, as opposed to potentially multiple interfaces that the class
2921+ implements.
2922+
2923+ :param interface: The interface the registered component will provide.
2924+
2925+ """
2926 scope = martian.CLASS
2927 store = martian.ONCE
2928 validate = martian.validateInterface
2929+
2930+ @classmethod
2931+ def get_default(cls, component, module, **data):
2932+ martian.util.check_implements_one(component)
2933+ return list(interface.implementedBy(component))[0]
2934
2935=== modified file 'src/grokcore/component/interfaces.py'
2936--- src/grokcore/component/interfaces.py 2010-01-29 16:22:17 +0000
2937+++ src/grokcore/component/interfaces.py 2013-01-23 22:26:20 +0000
2938@@ -1,6 +1,6 @@
2939 ##############################################################################
2940 #
2941-# Copyright (c) 2008 Zope Corporation and Contributors.
2942+# Copyright (c) 2008 Zope Foundation and Contributors.
2943 # All Rights Reserved.
2944 #
2945 # This software is subject to the provisions of the Zope Public License,
2946@@ -34,16 +34,24 @@
2947
2948
2949 class IBaseClasses(Interface):
2950+ Adapter = Attribute("Base class for adapters.")
2951
2952 ClassGrokker = Attribute("Base class to define a class grokker.")
2953+
2954+ Context = Attribute("Base class for automatically associated contexts.")
2955+
2956+ GlobalGrokker = Attribute("Base class to define a module grokker.")
2957+
2958+ GlobalUtility = Attribute("Base class for global utilities.")
2959+
2960 InstanceGrokker = Attribute("Base class to define an instance grokker.")
2961- GlobalGrokker = Attribute("Base class to define a module grokker.")
2962
2963- Context = Attribute("Base class for automatically associated contexts.")
2964-
2965- Adapter = Attribute("Base class for adapters.")
2966 MultiAdapter = Attribute("Base class for multi-adapters.")
2967- GlobalUtility = Attribute("Base class for global utilities.")
2968+
2969+ MultiSubscription = Attribute(
2970+ "Base class for subscription mult-adapters.")
2971+
2972+ Subscription = Attribute("Base class for subscription adapters.")
2973
2974
2975 class IDirectives(Interface):
2976@@ -57,13 +65,13 @@
2977
2978 def implements(*interfaces):
2979 """Declare that a class implements the given interfaces."""
2980-
2981+
2982 def implementsOnly(*interfaces):
2983 """Declare that a class implements only the given interfaces.
2984-
2985+
2986 Interfaces implemented by base classes are explicitly not inherited.
2987 """
2988-
2989+
2990 def classProvides(*interfaces):
2991 """Declare that a class (as opposed to instances of the class)
2992 directly provides the given interfaces.
2993@@ -130,6 +138,25 @@
2994 utility, or an instance of it.
2995 """
2996
2997+ def order(value=None):
2998+ """Control the ordering of components.
2999+
3000+ If the value is specified, the order will be determined by sorting on
3001+ it.
3002+ If no value is specified, the order will be determined by definition
3003+ order within the module.
3004+ If the directive is absent, the order will be determined by class name.
3005+ (unfortunately our preferred default behavior on absence which would
3006+ be like grok.order() without argument is hard to implement in Python)
3007+
3008+ Inter-module order is by dotted name of the module the
3009+ components are in; unless an explicit argument is specified to
3010+ ``grok.order()``, components are grouped by module.
3011+
3012+ The function grok.util.sort_components can be used to sort
3013+ components according to these rules.
3014+ """
3015+
3016
3017 class IDecorators(Interface):
3018
3019@@ -146,7 +173,7 @@
3020 """Describes that a function that's used as an adapter
3021 implements an interface or a number of interfaces.
3022 """
3023-
3024+
3025 def provider(*interfaces):
3026 """Describes that a function directly provides an interface or a
3027 number of interfaces.
3028@@ -164,15 +191,49 @@
3029
3030
3031 class IMartianAPI(Interface):
3032- """Part of Martian's API exposed by grokcore.component."""
3033-
3034- # This should probably move to martian at some point.
3035+ """Part of Martian's API exposed by grokcore.component.
3036+ """
3037
3038 ClassGrokker = Attribute("Grokker for classes.")
3039+
3040+ GlobalGrokker = Attribute("Grokker that's invoked for a module.")
3041+
3042 InstanceGrokker = Attribute("Grokker for instances.")
3043- GlobalGrokker = Attribute("Grokker that's invoked for a module.")
3044-
3045-
3046-class IGrokcoreComponentAPI(IBaseClasses, IDirectives, IDecorators,
3047- IGrokErrors, IMartianAPI):
3048- """grokcore.component's public API."""
3049+
3050+
3051+class IGrokcoreComponentAPI(
3052+ IBaseClasses,
3053+ IDecorators,
3054+ IDirectives,
3055+ IGrokErrors,
3056+ IMartianAPI,
3057+ ):
3058+ """grokcore.component's public API.
3059+ """
3060+
3061+ getSiteManager = Attribute('Get the site manager for the nearest site.')
3062+
3063+ provideAdapter = Attribute('Registers an adapters')
3064+
3065+ provideHandler = Attribute('Registers an handler')
3066+
3067+ provideInterface = Attribute('Regsiters an interfaces as a utility')
3068+
3069+ provideSubscriptionAdapter = Attribute(
3070+ 'Registers an subscriptions adapter')
3071+
3072+ provideUtility = Attribute('Registers an utility')
3073+
3074+ querySubscriptions = Attribute("Function to query subscriptions.")
3075+
3076+ queryOrderedSubscriptions = Attribute(
3077+ "Function to query subscription in order.")
3078+
3079+ queryMultiSubscriptions = Attribute("Function to query subscriptions.")
3080+
3081+ queryOrderedMultiSubscriptions = Attribute(
3082+ "Function to query subscriptions in order.")
3083+
3084+ sort_components = Attribute(
3085+ 'Sort a list of components using the information provided by '
3086+ '`grok.order`.')
3087
3088=== modified file 'src/grokcore/component/meta.py'
3089--- src/grokcore/component/meta.py 2010-01-29 16:22:17 +0000
3090+++ src/grokcore/component/meta.py 2013-01-23 22:26:20 +0000
3091@@ -1,6 +1,6 @@
3092 #############################################################################
3093 #
3094-# Copyright (c) 2006-2007 Zope Corporation and Contributors.
3095+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
3096 # All Rights Reserved.
3097 #
3098 # This software is subject to the provisions of the Zope Public License,
3099@@ -13,56 +13,37 @@
3100 ##############################################################################
3101 """Grokkers for the various components."""
3102
3103+import operator
3104+
3105 import martian
3106 import martian.util
3107 import grokcore.component
3108 import zope.component.interface
3109-
3110 from zope import component, interface
3111 from martian.error import GrokError
3112-from martian.util import scan_for_classes
3113-
3114-from grokcore.component.interfaces import IContext
3115-
3116-
3117-def default_provides(factory, module=None, **data):
3118- martian.util.check_implements_one(factory)
3119- return list(interface.implementedBy(factory))[0]
3120-
3121-def default_global_utility_provides(factory, module, direct, **data):
3122+from zope.interface import implementedBy
3123+
3124+def _provides(component, module=None, **data):
3125+ martian.util.check_implements_one(component)
3126+ return list(interface.implementedBy(component))[0]
3127+
3128+def default_global_utility_provides(component, module, direct, **data):
3129 if direct:
3130- martian.util.check_provides_one(factory)
3131- return list(interface.providedBy(factory))[0]
3132- return default_provides(factory)
3133+ martian.util.check_provides_one(component)
3134+ return list(interface.providedBy(component))[0]
3135+ return _provides(component)
3136
3137-def default_context(factory, module, **data):
3138- components = list(scan_for_classes(module, IContext))
3139- if len(components) == 0:
3140- raise GrokError(
3141- "No module-level context for %r, please use the 'context' "
3142- "directive." % (factory), factory)
3143- elif len(components) == 1:
3144- component = components[0]
3145- else:
3146- raise GrokError(
3147- "Multiple possible contexts for %r, please use the 'context' "
3148- "directive."
3149- % (factory), factory)
3150- return component
3151
3152 class AdapterGrokker(martian.ClassGrokker):
3153 martian.component(grokcore.component.Adapter)
3154+ martian.directive(grokcore.component.context)
3155+ martian.directive(grokcore.component.provides)
3156+ martian.directive(grokcore.component.name)
3157
3158- martian.directive(grokcore.component.context,
3159- get_default=default_context)
3160- martian.directive(grokcore.component.provides,
3161- get_default=default_provides)
3162- martian.directive(grokcore.component.name)
3163-
3164 def execute(self, factory, config, context, provides, name, **kw):
3165 config.action(
3166 discriminator=('adapter', context, provides, name),
3167- callable=component.provideAdapter,
3168+ callable=grokcore.component.provideAdapter,
3169 args=(factory, (context,), provides, name),
3170 )
3171 return True
3172@@ -70,26 +51,59 @@
3173
3174 class MultiAdapterGrokker(martian.ClassGrokker):
3175 martian.component(grokcore.component.MultiAdapter)
3176-
3177- martian.directive(grokcore.component.provides,
3178- get_default=default_provides)
3179+ martian.directive(grokcore.component.provides)
3180 martian.directive(grokcore.component.name)
3181
3182 def execute(self, factory, config, provides, name, **kw):
3183- if component.adaptedBy(factory) is None:
3184- raise GrokError("%r must specify which contexts it adapts "
3185- "(use the 'adapts' directive to specify)."
3186- % factory, factory)
3187 for_ = component.adaptedBy(factory)
3188+ if for_ is None:
3189+ raise GrokError("%r must specify which contexts it adapts "
3190+ "(use the 'adapts' directive to specify)."
3191+ % factory, factory)
3192
3193 config.action(
3194 discriminator=('adapter', for_, provides, name),
3195- callable=component.provideAdapter,
3196+ callable=grokcore.component.provideAdapter,
3197 args=(factory, None, provides, name),
3198 )
3199 return True
3200
3201
3202+class SubscriptionGrokker(martian.ClassGrokker):
3203+ martian.component(grokcore.component.Subscription)
3204+ martian.directive(grokcore.component.context)
3205+ martian.directive(grokcore.component.provides)
3206+ martian.directive(grokcore.component.name)
3207+
3208+ def execute(self, factory, config, context, provides, name, **kw):
3209+ config.action(
3210+ discriminator=None,
3211+ callable=grokcore.component.provideSubscriptionAdapter,
3212+ args=(factory, (context,), provides),
3213+ )
3214+ return True
3215+
3216+
3217+class MultiSubscriptionGrokker(martian.ClassGrokker):
3218+ martian.component(grokcore.component.MultiSubscription)
3219+ martian.directive(grokcore.component.provides)
3220+ martian.directive(grokcore.component.name)
3221+
3222+ def execute(self, factory, config, provides, name, **kw):
3223+ adapts = component.adaptedBy(factory)
3224+ if adapts is None:
3225+ raise GrokError("%r must specify which contexts it adapts "
3226+ "(use the 'adapts' directive to specify)."
3227+ % factory, factory)
3228+
3229+ config.action(
3230+ discriminator=None,
3231+ callable=grokcore.component.provideSubscriptionAdapter,
3232+ args=(factory, adapts, provides),
3233+ )
3234+ return True
3235+
3236+
3237 class GlobalUtilityGrokker(martian.ClassGrokker):
3238 martian.component(grokcore.component.GlobalUtility)
3239
3240@@ -108,30 +122,38 @@
3241
3242 config.action(
3243 discriminator=('utility', provides, name),
3244- callable=component.provideUtility,
3245+ callable=grokcore.component.provideUtility,
3246 args=(factory, provides, name),
3247 )
3248 return True
3249
3250-class AdapterDecoratorGrokker(martian.GlobalGrokker):
3251+
3252+class ImplementerDecoratorGrokker(martian.GlobalGrokker):
3253
3254 def grok(self, name, module, module_info, config, **kw):
3255 adapters = module_info.getAnnotation('grok.adapters', [])
3256+ subscribers = set(map(operator.itemgetter(0),
3257+ module_info.getAnnotation('grok.subscribers', [])))
3258+
3259 for function in adapters:
3260+ if function in subscribers:
3261+ # We don't register functions that are decorated with
3262+ # grok.implementer() *and* the grok.subscribe()
3263+ # decorator. These are registered as so called
3264+ # subcribers and not as regular adapters.
3265+ continue
3266 interfaces = getattr(function, '__component_adapts__', None)
3267 if interfaces is None:
3268- context = grokcore.component.context.bind(
3269- get_default=default_context).get(module)
3270+ context = grokcore.component.context.bind().get(module)
3271 interfaces = (context, )
3272 name = getattr(function, '__component_name__', u"")
3273 config.action(
3274 discriminator=('adapter', interfaces, function.__implemented__, name),
3275- callable=component.provideAdapter,
3276+ callable=grokcore.component.provideAdapter,
3277 args=(function, interfaces, function.__implemented__, name),
3278 )
3279 return True
3280
3281-
3282 class GlobalUtilityDirectiveGrokker(martian.GlobalGrokker):
3283
3284 def grok(self, name, module, module_info, config, **kw):
3285@@ -141,7 +163,8 @@
3286 if direct is None:
3287 direct = grokcore.component.direct.bind().get(factory)
3288 if provides is None:
3289- provides = grokcore.component.provides.bind().get(factory)
3290+ bound = grokcore.component.provides.bind(default=None)
3291+ provides = bound.get(factory)
3292 if not name:
3293 name = grokcore.component.name.bind().get(factory)
3294
3295@@ -153,55 +176,68 @@
3296 else:
3297 obj = factory()
3298 if provides is None:
3299- provides = default_provides(factory)
3300+ provides = _provides(factory)
3301
3302 config.action(
3303 discriminator=('utility', provides, name),
3304- callable=component.provideUtility,
3305+ callable=grokcore.component.provideUtility,
3306 args=(obj, provides, name),
3307 )
3308
3309 return True
3310
3311+
3312 class GlobalAdapterDirectiveGrokker(martian.GlobalGrokker):
3313
3314 def grok(self, name, module, module_info, config, **kw):
3315 infos = grokcore.component.global_adapter.bind().get(module)
3316 for factory, adapts, provides, name in infos:
3317 if provides is None:
3318- provides = grokcore.component.provides.bind().get(factory)
3319+ bound = grokcore.component.provides.bind(default=None)
3320+ provides = bound.get(factory)
3321 if adapts is None:
3322- adapts = getattr(factory, '__component_adapts__', None)
3323- if adapts is None:
3324- adapts = grokcore.component.context.bind(
3325- get_default=default_context).get(factory)
3326- if not name:
3327+ adapts = (grokcore.component.context.bind().get(module),)
3328+ if name is None:
3329 name = grokcore.component.name.bind().get(factory)
3330-
3331+
3332 config.action(
3333 discriminator=('adapter', adapts, provides, name),
3334- callable=component.provideAdapter,
3335+ callable=grokcore.component.provideAdapter,
3336 args=(factory, adapts, provides, name),
3337 )
3338
3339 return True
3340
3341-class SubscriberGrokker(martian.GlobalGrokker):
3342+
3343+class SubscriberDirectiveGrokker(martian.GlobalGrokker):
3344
3345 def grok(self, name, module, module_info, config, **kw):
3346 subscribers = module_info.getAnnotation('grok.subscribers', [])
3347
3348 for factory, subscribed in subscribers:
3349- config.action(
3350- discriminator=None,
3351- callable=component.provideHandler,
3352- args=(factory, subscribed),
3353- )
3354+ provides = None
3355+ implemented = list(implementedBy(factory))
3356+ if len(implemented) == 1:
3357+ provides = implemented[0]
3358+ # provideHandler is essentially the same as
3359+ # provideSubscriptionAdapter, where provided=None. However,
3360+ # handlers and subscription adapters are tracked in
3361+ # separately so we cannot exchange one registration call
3362+ # for the the other.
3363+ if provides is None:
3364+ config.action(
3365+ discriminator=None,
3366+ callable=grokcore.component.provideHandler,
3367+ args=(factory, subscribed))
3368+ else:
3369+ config.action(
3370+ discriminator=None,
3371+ callable=grokcore.component.provideSubscriptionAdapter,
3372+ args=(factory, subscribed, provides))
3373
3374 for iface in subscribed:
3375 config.action(
3376 discriminator=None,
3377- callable=zope.component.interface.provideInterface,
3378- args=('', iface)
3379- )
3380+ callable=grokcore.component.provideInterface,
3381+ args=('', iface))
3382 return True
3383
3384=== added file 'src/grokcore/component/subscription.py'
3385--- src/grokcore/component/subscription.py 1970-01-01 00:00:00 +0000
3386+++ src/grokcore/component/subscription.py 2013-01-23 22:26:20 +0000
3387@@ -0,0 +1,41 @@
3388+##############################################################################
3389+#
3390+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
3391+# All Rights Reserved.
3392+#
3393+# This software is subject to the provisions of the Zope Public License,
3394+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
3395+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
3396+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3397+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
3398+# FOR A PARTICULAR PURPOSE.
3399+#
3400+##############################################################################
3401+"""Grok subscriptions functions.
3402+"""
3403+from zope import component
3404+from grokcore.component import util
3405+
3406+def queryOrderedMultiSubscriptions(components, interface):
3407+ return util.sort_components(component.subscribers(components, interface))
3408+
3409+def queryOrderedSubscriptions(component, interface):
3410+ return queryOrderedMultiSubscriptions((component, ), interface)
3411+
3412+def queryMultiSubscriptions(components, interface):
3413+ """Query for subscriptions on the `components` providing `interface`.
3414+
3415+ :parameter components: tuple of components to lookup the subscription for.
3416+ :parameter interface: interface that the subscriptions should provide.
3417+ :return: a list of subscriptions.
3418+ """
3419+ return component.subscribers(components, interface)
3420+
3421+def querySubscriptions(component, interface):
3422+ """Query for subscriptions on `component` providing `interface`.
3423+
3424+ :parameter component: a component to lookup the subscriptions for.
3425+ :parameter interface: interface that the subscriptions should provide.
3426+ :return: a list of subscription.
3427+ """
3428+ return queryMultiSubscriptions((component,), interface)
3429
3430=== modified file 'src/grokcore/component/testing.py'
3431--- src/grokcore/component/testing.py 2010-01-29 16:22:17 +0000
3432+++ src/grokcore/component/testing.py 2013-01-23 22:26:20 +0000
3433@@ -1,6 +1,6 @@
3434 ##############################################################################
3435 #
3436-# Copyright (c) 2007 Zope Corporation and Contributors.
3437+# Copyright (c) 2007 Zope Foundation and Contributors.
3438 # All Rights Reserved.
3439 #
3440 # This software is subject to the provisions of the Zope Public License,
3441
3442=== modified file 'src/grokcore/component/tests/adapter/globaladapter.py'
3443--- src/grokcore/component/tests/adapter/globaladapter.py 2010-01-29 16:22:17 +0000
3444+++ src/grokcore/component/tests/adapter/globaladapter.py 2013-01-23 22:26:20 +0000
3445@@ -1,77 +1,103 @@
3446 """
3447 >>> grok.testing.grok(__name__)
3448 >>> from zope.component import getAdapter, getMultiAdapter
3449-
3450+
3451 >>> cave = Cave()
3452 >>> fireplace = Fireplace()
3453-
3454+
3455 >>> home = IHome(cave)
3456 >>> home.id
3457 u'one'
3458-
3459+
3460 >>> home = getAdapter(cave, IHome, name=u"two")
3461 >>> home.id
3462 u'two'
3463-
3464+
3465 >>> home = getAdapter(cave, IHome, name=u"three")
3466 >>> home.id
3467 u'three'
3468-
3469+
3470 >>> home = getAdapter(cave, IHome, name=u"four")
3471 >>> home.id
3472 u'four'
3473-
3474+
3475 >>> home = getAdapter(fireplace, IHome, name=u"five")
3476 >>> home.id
3477 u'five'
3478-
3479+
3480 >>> home = getMultiAdapter((cave, fireplace), IHome)
3481 >>> home.id
3482 u'six'
3483-
3484+
3485+ >>> home = getAdapter(fireplace, IHome, name=u'seven')
3486+ >>> home.id
3487+ u'seven-a'
3488+
3489+ >>> home = getMultiAdapter((cave, fireplace), IHome, name=u'seven')
3490+ >>> home.id
3491+ u'seven-b'
3492+
3493+ >>> garage = getAdapter(cave, IGarage, name='named_garage_factory_name')
3494+ >>> garage.id
3495+ u"I'm a garage"
3496+
3497+ >>> garage = getAdapter(cave, IGarage)
3498+ >>> garage.id
3499+ u"I'm a garage"
3500+
3501 """
3502
3503 import grokcore.component as grok
3504 from zope import interface
3505 from zope.interface import implementer
3506
3507+
3508 class Cave(grok.Context):
3509 pass
3510
3511+
3512 class Fireplace(object):
3513 pass
3514
3515+
3516 class IHome(interface.Interface):
3517 pass
3518
3519+
3520 class Home(object):
3521 grok.implements(IHome)
3522-
3523+
3524 def __init__(self, id):
3525 self.id = id
3526
3527+
3528 class CaveHomeFactory(object):
3529 grok.implements(IHome)
3530-
3531+
3532 def __init__(self, id):
3533 self.id = id
3534-
3535+
3536 def __call__(self, context):
3537 return Home(self.id)
3538
3539+
3540 class CaveFireplaceHomeFactory(object):
3541+
3542 def __init__(self, id):
3543 self.id = id
3544-
3545+
3546 def __call__(self, cave, fireplace):
3547 return Home(self.id)
3548
3549+
3550 factory1 = CaveHomeFactory(u"one")
3551 factory2 = CaveHomeFactory(u"two")
3552 factory3 = CaveHomeFactory(u"three")
3553 factory4 = CaveHomeFactory(u"four")
3554 factory5 = CaveHomeFactory(u"five")
3555 factory6 = CaveFireplaceHomeFactory(u"six")
3556+factory7a = CaveHomeFactory(u"seven-a")
3557+factory7b = CaveFireplaceHomeFactory(u"seven-b")
3558
3559 # make some direct assertions
3560
3561@@ -79,12 +105,45 @@
3562 implementer(IHome)(factory4)
3563 implementer(IHome)(factory5)
3564 implementer(IHome)(factory6)
3565+implementer(IHome)(factory7a)
3566+implementer(IHome)(factory7b)
3567
3568 grok.adapter(Fireplace)(factory5)
3569-
3570-grok.global_adapter(factory1, Cave, IHome) # should accept single value for adapts
3571-grok.global_adapter(factory2, (Cave,), IHome, name="two") # should accept tuple for adapts
3572-grok.global_adapter(factory3, Cave, name="three") # should look at the provided interface
3573-grok.global_adapter(factory4, name=u"four") # should pick the canonical context
3574-grok.global_adapter(factory5, name="five") # should use __component_adapts__
3575-grok.global_adapter(factory6, (Cave, Fireplace,)) # should work as multi-adapter
3576+grok.adapter(Fireplace)(factory7a)
3577+grok.adapter(Cave, Fireplace)(factory7b)
3578+
3579+# should accept single value for adapts
3580+grok.global_adapter(factory1, Cave, IHome)
3581+# should accept tuple for adapts
3582+grok.global_adapter(factory2, (Cave,), IHome, name=u"two")
3583+# should look at the provided interface
3584+grok.global_adapter(factory3, Cave, name=u"three")
3585+# should pick the canonical context
3586+grok.global_adapter(factory4, name=u"four")
3587+# should use __component_adapts__
3588+grok.global_adapter(factory5, name=u"five")
3589+# should work as multi-adapter
3590+grok.global_adapter(factory6, (Cave, Fireplace,))
3591+# should use __component_adapts__ adapting one object
3592+grok.global_adapter(factory7a, name=u"seven")
3593+# should use __component_adapts__ adaping two objects
3594+grok.global_adapter(factory7b, name=u"seven")
3595+
3596+
3597+class IGarage(interface.Interface):
3598+ pass
3599+
3600+
3601+class NamedGarageFactory(object):
3602+ grok.implements(IGarage)
3603+ grok.name('named_garage_factory_name')
3604+
3605+ def __init__(self, context):
3606+ self.id = u"I'm a garage"
3607+
3608+implementer(IGarage)(NamedGarageFactory)
3609+
3610+# should register a named adapter
3611+grok.global_adapter(NamedGarageFactory, Cave, IGarage)
3612+# should override component's name
3613+grok.global_adapter(NamedGarageFactory, Cave, IGarage, name=u'')
3614
3615=== modified file 'src/grokcore/component/tests/adapter/nomodel.py'
3616--- src/grokcore/component/tests/adapter/nomodel.py 2010-01-29 16:22:17 +0000
3617+++ src/grokcore/component/tests/adapter/nomodel.py 2013-01-23 22:26:20 +0000
3618@@ -5,7 +5,8 @@
3619 Traceback (most recent call last):
3620 ...
3621 GrokError: No module-level context for
3622- <class 'grokcore.component.tests.adapter.nomodel.Home'>, please use the 'context' directive.
3623+ <class 'grokcore.component.tests.adapter.nomodel.Home'>, please use the
3624+ 'context' directive.
3625
3626 """
3627 import grokcore.component as grok
3628
3629=== modified file 'src/grokcore/component/tests/event/subscriber.py'
3630--- src/grokcore/component/tests/event/subscriber.py 2010-01-29 16:22:17 +0000
3631+++ src/grokcore/component/tests/event/subscriber.py 2013-01-23 22:26:20 +0000
3632@@ -8,9 +8,9 @@
3633 ['Manfred']
3634 >>> mammoths2
3635 ['Manfred']
3636-
3637-The decorated event handling function can also be called directly:
3638-
3639+
3640+The decorated event handling function can also be called directly:
3641+
3642 >>> mammothAdded(Mammoth('Max'),None)
3643 >>> mammoths
3644 ['Manfred', 'Max']
3645
3646=== added directory 'src/grokcore/component/tests/order'
3647=== added file 'src/grokcore/component/tests/order/__init__.py'
3648--- src/grokcore/component/tests/order/__init__.py 1970-01-01 00:00:00 +0000
3649+++ src/grokcore/component/tests/order/__init__.py 2013-01-23 22:26:20 +0000
3650@@ -0,0 +1,1 @@
3651+#
3652
3653=== added file 'src/grokcore/component/tests/order/arg_orderdirective.py'
3654--- src/grokcore/component/tests/order/arg_orderdirective.py 1970-01-01 00:00:00 +0000
3655+++ src/grokcore/component/tests/order/arg_orderdirective.py 2013-01-23 22:26:20 +0000
3656@@ -0,0 +1,42 @@
3657+"""
3658+If the grok.order directive is present with arguments, sorting will be
3659+done by the order specified.
3660+
3661+ >>> from grokcore.component import sort_components
3662+
3663+ >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
3664+ >>> sort_components(components)
3665+ [<...Fifth object at ...>,
3666+ <...Fourth object at ...>,
3667+ <...Third object at ...>,
3668+ <...Second object at ...>,
3669+ <...First object at ...>]
3670+
3671+You can use the key option:
3672+
3673+ >>> from operator import itemgetter
3674+
3675+ >>> components = [(1, First()), (2, Second()), (3, Third())]
3676+ >>> sort_components(components, key=itemgetter(1))
3677+ [(3, <...Third object at ...>),
3678+ (2, <...Second object at ...>),
3679+ (1, <...First object at ...>)]
3680+
3681+"""
3682+
3683+import grokcore.component as grok
3684+
3685+class First(object):
3686+ grok.order(5)
3687+
3688+class Second(object):
3689+ grok.order(4)
3690+
3691+class Third(object):
3692+ grok.order(3)
3693+
3694+class Fourth(object):
3695+ grok.order(2)
3696+
3697+class Fifth(object):
3698+ grok.order(1)
3699
3700=== added file 'src/grokcore/component/tests/order/combined_orderdirective.py'
3701--- src/grokcore/component/tests/order/combined_orderdirective.py 1970-01-01 00:00:00 +0000
3702+++ src/grokcore/component/tests/order/combined_orderdirective.py 2013-01-23 22:26:20 +0000
3703@@ -0,0 +1,34 @@
3704+"""
3705+
3706+If the grok.order directive is specified with other classes that don't
3707+have the order specified, then the order will be determined by first
3708+sorting on the order specified, and then by the definition order.
3709+
3710+ >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
3711+
3712+ >>> from grokcore.component import sort_components
3713+ >>> sort_components(components)
3714+ [<...Third object at ...>,
3715+ <...Fourth object at ...>,
3716+ <...Second object at ...>,
3717+ <...Fifth object at ...>,
3718+ <...First object at ...>]
3719+
3720+"""
3721+
3722+import grokcore.component as grok
3723+
3724+class First(object):
3725+ grok.order(2)
3726+
3727+class Second(object):
3728+ grok.order(1)
3729+
3730+class Third(object):
3731+ grok.order()
3732+
3733+class Fourth(object):
3734+ grok.order()
3735+
3736+class Fifth(object):
3737+ grok.order(1)
3738
3739=== added file 'src/grokcore/component/tests/order/combinednoorder_orderdirective.py'
3740--- src/grokcore/component/tests/order/combinednoorder_orderdirective.py 1970-01-01 00:00:00 +0000
3741+++ src/grokcore/component/tests/order/combinednoorder_orderdirective.py 2013-01-23 22:26:20 +0000
3742@@ -0,0 +1,34 @@
3743+"""
3744+
3745+If the grok.order directive is specified with other classes that don't
3746+have the order specified, then the order will be determined by first
3747+sorting on the order specified, and then by the definition order.
3748+
3749+ >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
3750+
3751+ >>> from grokcore.component import sort_components
3752+ >>> sort_components(components)
3753+ [<...Fifth object at ...>,
3754+ <...Third object at ...>,
3755+ <...First object at ...>,
3756+ <...Fourth object at ...>,
3757+ <...Second object at ...>]
3758+
3759+"""
3760+
3761+import grokcore.component as grok
3762+
3763+class First(object):
3764+ grok.order()
3765+
3766+class Second(object):
3767+ grok.order(1)
3768+
3769+class Third(object):
3770+ pass
3771+
3772+class Fourth(object):
3773+ grok.order()
3774+
3775+class Fifth(object):
3776+ pass
3777
3778=== added file 'src/grokcore/component/tests/order/inter1.py'
3779--- src/grokcore/component/tests/order/inter1.py 1970-01-01 00:00:00 +0000
3780+++ src/grokcore/component/tests/order/inter1.py 2013-01-23 22:26:20 +0000
3781@@ -0,0 +1,35 @@
3782+"""
3783+
3784+The ordering works like so:
3785+1. Objects with explicit ordering
3786+ (if combined with objects with no ordering not specified, then the orderless
3787+ objects come first)
3788+2. Objects with same ordering get grouped by module import order
3789+3. Internal order within module
3790+4. If no ordering is specified by any objects, then objects are sorted
3791+ alphabetically by class name
3792+
3793+ >>> from inter2 import Four, Five, Six
3794+ >>> components = [One(), Two(), Three(), Four(), Five(), Six()]
3795+
3796+ >>> from grokcore.component import sort_components
3797+ >>> sort_components(components)
3798+ [<...Three object at ...>,
3799+ <...One object at ...>,
3800+ <...Five object at ...>,
3801+ <...Six object at ...>,
3802+ <...Four object at ...>,
3803+ <...Two object at ...>]
3804+
3805+"""
3806+
3807+import grokcore.component as grok
3808+
3809+class One(object):
3810+ grok.order()
3811+
3812+class Two(object):
3813+ grok.order(2)
3814+
3815+class Three(object):
3816+ pass
3817
3818=== added file 'src/grokcore/component/tests/order/inter2.py'
3819--- src/grokcore/component/tests/order/inter2.py 1970-01-01 00:00:00 +0000
3820+++ src/grokcore/component/tests/order/inter2.py 2013-01-23 22:26:20 +0000
3821@@ -0,0 +1,14 @@
3822+"""
3823+This module used by inter1 tests
3824+"""
3825+
3826+import grokcore.component as grok
3827+
3828+class Four(object):
3829+ grok.order(1)
3830+
3831+class Five(object):
3832+ pass
3833+
3834+class Six(object):
3835+ grok.order()
3836
3837=== added file 'src/grokcore/component/tests/order/noarg_orderdirective.py'
3838--- src/grokcore/component/tests/order/noarg_orderdirective.py 1970-01-01 00:00:00 +0000
3839+++ src/grokcore/component/tests/order/noarg_orderdirective.py 2013-01-23 22:26:20 +0000
3840@@ -0,0 +1,33 @@
3841+"""
3842+
3843+If the grok.order directive is present with no arguments, sorting will
3844+be done by definition order.
3845+
3846+ >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
3847+
3848+ >>> from grokcore.component import sort_components
3849+ >>> sort_components(components)
3850+ [<...First object at ...>,
3851+ <...Second object at ...>,
3852+ <...Third object at ...>,
3853+ <...Fourth object at ...>,
3854+ <...Fifth object at ...>]
3855+
3856+"""
3857+
3858+import grokcore.component as grok
3859+
3860+class First(object):
3861+ grok.order()
3862+
3863+class Second(object):
3864+ grok.order()
3865+
3866+class Third(object):
3867+ grok.order()
3868+
3869+class Fourth(object):
3870+ grok.order()
3871+
3872+class Fifth(object):
3873+ grok.order()
3874
3875=== added file 'src/grokcore/component/tests/order/nodirective.py'
3876--- src/grokcore/component/tests/order/nodirective.py 1970-01-01 00:00:00 +0000
3877+++ src/grokcore/component/tests/order/nodirective.py 2013-01-23 22:26:20 +0000
3878@@ -0,0 +1,31 @@
3879+"""
3880+
3881+If the grok.order directive is absent, sorting will be done by class
3882+name.
3883+
3884+ >>> components = [First(), Second(), Third(), Fourth(), Fifth()]
3885+
3886+ >>> from grokcore.component import sort_components
3887+ >>> sort_components(components)
3888+ [<...Fifth object at ...>,
3889+ <...First object at ...>,
3890+ <...Fourth object at ...>,
3891+ <...Second object at ...>,
3892+ <...Third object at ...>]
3893+
3894+"""
3895+
3896+class First(object):
3897+ pass
3898+
3899+class Second(object):
3900+ pass
3901+
3902+class Third(object):
3903+ pass
3904+
3905+class Fourth(object):
3906+ pass
3907+
3908+class Fifth(object):
3909+ pass
3910
3911=== added directory 'src/grokcore/component/tests/subscriptions'
3912=== added file 'src/grokcore/component/tests/subscriptions/__init__.py'
3913--- src/grokcore/component/tests/subscriptions/__init__.py 1970-01-01 00:00:00 +0000
3914+++ src/grokcore/component/tests/subscriptions/__init__.py 2013-01-23 22:26:20 +0000
3915@@ -0,0 +1,1 @@
3916+# this is a package
3917
3918=== added file 'src/grokcore/component/tests/subscriptions/decorator.py'
3919--- src/grokcore/component/tests/subscriptions/decorator.py 1970-01-01 00:00:00 +0000
3920+++ src/grokcore/component/tests/subscriptions/decorator.py 2013-01-23 22:26:20 +0000
3921@@ -0,0 +1,41 @@
3922+"""
3923+ >>> grok.testing.grok(__name__)
3924+
3925+ >>> cave = Cave('sweet home')
3926+
3927+ >>> subscriptions = grok.querySubscriptions(cave, IActivity)
3928+ >>> subscriptions
3929+ [<grokcore.component.tests.subscriptions.decorator.DebuggingGrokcore object at ...>]
3930+
3931+ Subscription adapters are not registered as regular adapters:
3932+
3933+ >>> from zope import component
3934+ >>> component.queryAdapter(cave, IActivity)
3935+
3936+"""
3937+
3938+
3939+import grokcore.component as grok
3940+from zope import interface
3941+
3942+
3943+class Cave(grok.Context):
3944+
3945+ def __init__(self, name):
3946+ self.name = name
3947+
3948+
3949+class IActivity(interface.Interface):
3950+ pass
3951+
3952+
3953+class DebuggingGrokcore(object):
3954+
3955+ def __init__(self, where):
3956+ self.where = where
3957+
3958+
3959+@grok.subscribe(Cave)
3960+@grok.implementer(IActivity)
3961+def debugging(content):
3962+ return DebuggingGrokcore(content)
3963
3964=== added file 'src/grokcore/component/tests/subscriptions/multisubscriptions.py'
3965--- src/grokcore/component/tests/subscriptions/multisubscriptions.py 1970-01-01 00:00:00 +0000
3966+++ src/grokcore/component/tests/subscriptions/multisubscriptions.py 2013-01-23 22:26:20 +0000
3967@@ -0,0 +1,98 @@
3968+"""
3969+ >>> grok.testing.grok(__name__)
3970+
3971+ >>> cave = Cave('Tilburg cave')
3972+ >>> martijn = Mammoth('Martijn')
3973+
3974+ You can query a subscriptions using multiple components. You will get
3975+ all subscriptions registered for office and cave (since office is a
3976+ base class of cave):
3977+
3978+ >>> subscriptions = grok.queryMultiSubscriptions((cave, martijn), IActivity)
3979+ >>> subscriptions
3980+ [<grokcore.component.tests.subscriptions.multisubscriptions.Sleep object at ...>,
3981+ <grokcore.component.tests.subscriptions.multisubscriptions.Food object at ...>,
3982+ <grokcore.component.tests.subscriptions.multisubscriptions.WritingCode object at ...>]
3983+
3984+ >>> _ = map(lambda s: s.do(), subscriptions)
3985+ Martijn is sleeping at Tilburg cave.
3986+ Martijn is feeding himself at Tilburg cave.
3987+ Martijn is writing code at Tilburg cave!
3988+
3989+
3990+ Now, Martijn goes to the office. You will only get subscriptions
3991+ registered for office:
3992+
3993+ >>> office = Office('Grok corp(r)(tm) headquarters')
3994+ >>> office_subscriptions = grok.queryMultiSubscriptions(
3995+ ... (office, martijn), IActivity)
3996+ >>> office_subscriptions
3997+ [<grokcore.component.tests.subscriptions.multisubscriptions.Sleep object at ...>]
3998+
3999+ >>> _ = map(lambda s: s.do(), office_subscriptions)
4000+ Martijn is sleeping at Grok corp(r)(tm) headquarters.
4001+
4002+"""
4003+
4004+import grokcore.component as grok
4005+from zope import interface
4006+
4007+
4008+class Office(grok.Context):
4009+
4010+ def __init__(self, name):
4011+ self.name = name
4012+
4013+
4014+# All caves are a kind of office.
4015+class Cave(Office):
4016+ pass
4017+
4018+
4019+class Mammoth(grok.Context):
4020+
4021+ def __init__(self, name):
4022+ self.name = name
4023+
4024+
4025+class IActivity(interface.Interface):
4026+
4027+ def do():
4028+ """Do something.
4029+ """
4030+
4031+class Sleep(grok.MultiSubscription):
4032+ grok.implements(IActivity)
4033+ grok.adapts(Office, Mammoth)
4034+
4035+ def __init__(self, where, who):
4036+ self.where = where
4037+ self.who = who
4038+
4039+ def do(self):
4040+ print '%s is sleeping at %s.' % (self.who.name, self.where.name)
4041+
4042+
4043+class DayTimeActivity(grok.MultiSubscription):
4044+ grok.implements(IActivity)
4045+ grok.adapts(Cave, Mammoth)
4046+ grok.baseclass()
4047+
4048+ def __init__(self, where, who):
4049+ self.where = where
4050+ self.who = who
4051+
4052+ def do(self):
4053+ print 'nothing'
4054+
4055+
4056+class Food(DayTimeActivity):
4057+
4058+ def do(self):
4059+ print '%s is feeding himself at %s.' % (self.who.name, self.where.name)
4060+
4061+
4062+class WritingCode(DayTimeActivity):
4063+
4064+ def do(self):
4065+ print '%s is writing code at %s!' % (self.who.name, self.where.name)
4066
4067=== added file 'src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py'
4068--- src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py 1970-01-01 00:00:00 +0000
4069+++ src/grokcore/component/tests/subscriptions/multisubscriptions_no_adapts.py 2013-01-23 22:26:20 +0000
4070@@ -0,0 +1,19 @@
4071+"""
4072+ >>> grok.testing.grok(__name__)
4073+ Traceback (most recent call last):
4074+ ...
4075+ GrokError: <class 'grokcore.component.tests.subscriptions.multisubscriptions_no_adapts.CaveGardenRenovator'>
4076+ must specify which contexts it adapts (use the 'adapts' directive to specify).
4077+
4078+"""
4079+
4080+import grokcore.component as grok
4081+from zope import interface
4082+
4083+class IRenovate(interface.Interface):
4084+
4085+ def takedown():
4086+ pass
4087+
4088+class CaveGardenRenovator(grok.MultiSubscription):
4089+ grok.provides(IRenovate)
4090
4091=== added file 'src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py'
4092--- src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py 1970-01-01 00:00:00 +0000
4093+++ src/grokcore/component/tests/subscriptions/multisubscriptions_no_interface.py 2013-01-23 22:26:20 +0000
4094@@ -0,0 +1,20 @@
4095+"""
4096+ >>> grok.testing.grok(__name__)
4097+ Traceback (most recent call last):
4098+ ...
4099+ GrokError: <class 'grokcore.component.tests.subscriptions.multisubscriptions_no_interface.CaveGardenRedecorator'>
4100+ must implement at least one interface (use grok.implements to specify).
4101+
4102+"""
4103+
4104+import grokcore.component as grok
4105+
4106+
4107+class Cave(grok.Context):
4108+ pass
4109+
4110+class Garden(grok.Context):
4111+ pass
4112+
4113+class CaveGardenRedecorator(grok.MultiSubscription):
4114+ pass
4115
4116=== added file 'src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py'
4117--- src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py 1970-01-01 00:00:00 +0000
4118+++ src/grokcore/component/tests/subscriptions/ordered_multisubscriptions.py 2013-01-23 22:26:20 +0000
4119@@ -0,0 +1,97 @@
4120+"""
4121+ >>> grok.testing.grok(__name__)
4122+
4123+ >>> cave = Cave('Tilburg cave')
4124+ >>> martijn = Mammoth('Martijn')
4125+
4126+ You can query a subscriptions using multiple components and sort them
4127+ using `grok.order` information:
4128+
4129+ >>> ordered_subscriptions = grok.queryOrderedMultiSubscriptions(
4130+ ... (cave, martijn), IActivity)
4131+ >>> ordered_subscriptions
4132+ [<grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cooking object at ...>,
4133+ <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Gardening object at ...>,
4134+ <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cleaning object at ...>]
4135+
4136+ >>> _ = map(lambda a: a.do(), ordered_subscriptions)
4137+ Martijn is cooking in Tilburg cave!
4138+ Martijn is growing pumpkins in Tilburg cave!
4139+ Martijn is cleaning the Tilburg cave.
4140+
4141+ Or choose not to:
4142+
4143+ >>> subscriptions = grok.queryMultiSubscriptions(
4144+ ... (cave, martijn), IActivity)
4145+
4146+ (still need to sort them on class name in order to have a working doctest)
4147+
4148+ >>> subscriptions = sorted(subscriptions, key=lambda s: s.__class__.__name__)
4149+ >>> subscriptions
4150+ [<grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cleaning object at ...>,
4151+ <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Cooking object at ...>,
4152+ <grokcore.component.tests.subscriptions.ordered_multisubscriptions.Gardening object at ...>]
4153+
4154+ >>> _ = map(lambda a: a.do(), subscriptions)
4155+ Martijn is cleaning the Tilburg cave.
4156+ Martijn is cooking in Tilburg cave!
4157+ Martijn is growing pumpkins in Tilburg cave!
4158+
4159+
4160+"""
4161+
4162+import grokcore.component as grok
4163+from zope import interface
4164+
4165+
4166+class Cave(grok.Context):
4167+
4168+ def __init__(self, name):
4169+ self.name = name
4170+
4171+
4172+class Mammoth(grok.Context):
4173+
4174+ def __init__(self, name):
4175+ self.name = name
4176+
4177+
4178+class IActivity(interface.Interface):
4179+
4180+ def do():
4181+ """Do something.
4182+ """
4183+
4184+
4185+class DayTimeActivity(grok.MultiSubscription):
4186+ grok.provides(IActivity)
4187+ grok.adapts(Cave, Mammoth)
4188+ grok.baseclass()
4189+
4190+ def __init__(self, where, who):
4191+ self.where = where
4192+ self.who = who
4193+
4194+ def do(self):
4195+ print 'Doing nothing.'
4196+
4197+
4198+class Cleaning(DayTimeActivity):
4199+ grok.order(99)
4200+
4201+ def do(self):
4202+ print '%s is cleaning the %s.' % (self.who.name, self.where.name)
4203+
4204+
4205+class Cooking(DayTimeActivity):
4206+ grok.order(10)
4207+
4208+ def do(self):
4209+ print '%s is cooking in %s!' % (self.who.name, self.where.name)
4210+
4211+
4212+class Gardening(DayTimeActivity):
4213+ grok.order(15)
4214+
4215+ def do(self):
4216+ print '%s is growing pumpkins in %s!' % (self.who.name, self.where.name)
4217
4218=== added file 'src/grokcore/component/tests/subscriptions/ordered_subscriptions.py'
4219--- src/grokcore/component/tests/subscriptions/ordered_subscriptions.py 1970-01-01 00:00:00 +0000
4220+++ src/grokcore/component/tests/subscriptions/ordered_subscriptions.py 2013-01-23 22:26:20 +0000
4221@@ -0,0 +1,71 @@
4222+"""
4223+ >>> grok.testing.grok(__name__)
4224+
4225+ >>> cave = Cave()
4226+
4227+ You can query the subscriptions and sort them with the information
4228+ provided by grok.order:
4229+
4230+ >>> ordered_subscriptions = grok.queryOrderedSubscriptions(cave, ICleaner)
4231+ >>> ordered_subscriptions
4232+ [<grokcore.component.tests.subscriptions.ordered_subscriptions.MondayCleaner object at ...>,
4233+ <grokcore.component.tests.subscriptions.ordered_subscriptions.WednesdayCleaner object at ...>,
4234+ <grokcore.component.tests.subscriptions.ordered_subscriptions.SaturdayCleaner object at ...>]
4235+
4236+ >>> _ = map(lambda s: s.work(), ordered_subscriptions)
4237+ Monday cleaning!
4238+ Wednesday cleaning!
4239+ Saturday cleaning!
4240+
4241+ If you use the regular query method, they won't be sorted:
4242+
4243+ >>> subscriptions = grok.querySubscriptions(cave, ICleaner)
4244+ >>> subscriptions
4245+ [<grokcore.component.tests.subscriptions.ordered_subscriptions.MondayCleaner object at ...>,
4246+ <grokcore.component.tests.subscriptions.ordered_subscriptions.SaturdayCleaner object at ...>,
4247+ <grokcore.component.tests.subscriptions.ordered_subscriptions.WednesdayCleaner object at ...>]
4248+
4249+ >>> _ = map(lambda s: s.work(), subscriptions)
4250+ Monday cleaning!
4251+ Saturday cleaning!
4252+ Wednesday cleaning!
4253+
4254+"""
4255+
4256+import grokcore.component as grok
4257+from zope import interface
4258+
4259+
4260+class Cave(grok.Context):
4261+ pass
4262+
4263+
4264+class ICleaner(interface.Interface):
4265+
4266+ def work():
4267+ """Clean that cave.
4268+ """
4269+
4270+class MondayCleaner(grok.Subscription):
4271+ grok.implements(ICleaner)
4272+ grok.order(1)
4273+
4274+ def work(self):
4275+ print 'Monday cleaning!'
4276+
4277+
4278+class WednesdayCleaner(grok.Subscription):
4279+ grok.implements(ICleaner)
4280+ grok.order(3)
4281+
4282+ def work(self):
4283+ print 'Wednesday cleaning!'
4284+
4285+
4286+class SaturdayCleaner(grok.Subscription):
4287+ grok.implements(ICleaner)
4288+ grok.order(6)
4289+
4290+ def work(self):
4291+ print 'Saturday cleaning!'
4292+
4293
4294=== added file 'src/grokcore/component/tests/subscriptions/subscriptions.py'
4295--- src/grokcore/component/tests/subscriptions/subscriptions.py 1970-01-01 00:00:00 +0000
4296+++ src/grokcore/component/tests/subscriptions/subscriptions.py 2013-01-23 22:26:20 +0000
4297@@ -0,0 +1,58 @@
4298+"""
4299+ >>> grok.testing.grok(__name__)
4300+
4301+ >>> cave = Cave('sweet home')
4302+
4303+ >>> subscriptions = grok.querySubscriptions(cave, ICleaner)
4304+ >>> subscriptions
4305+ [<grokcore.component.tests.subscriptions.subscriptions.MondayCleaner object at ...>,
4306+ <grokcore.component.tests.subscriptions.subscriptions.SaturdayCleaner object at ...>,
4307+ <grokcore.component.tests.subscriptions.subscriptions.WednesdayCleaner object at ...>]
4308+
4309+ >>> _ = map(lambda s: s.work(), subscriptions)
4310+ Monday cleaning sweet home!
4311+ Saturday cleaning sweet home!
4312+ Wednesday cleaning sweet home!
4313+
4314+ Subscription adapters are not registered as regular adapters:
4315+
4316+ >>> component.queryAdapter(cave, ICleaner)
4317+
4318+"""
4319+
4320+import grokcore.component as grok
4321+from zope import interface, component
4322+
4323+
4324+class Cave(grok.Context):
4325+
4326+ def __init__(self, name):
4327+ self.name = name
4328+
4329+
4330+class ICleaner(interface.Interface):
4331+
4332+ def work():
4333+ """Clean that cave.
4334+ """
4335+
4336+class MondayCleaner(grok.Subscription):
4337+ grok.implements(ICleaner)
4338+
4339+ def work(self):
4340+ print 'Monday cleaning %s!' % self.context.name
4341+
4342+
4343+class WednesdayCleaner(grok.Subscription):
4344+ grok.provides(ICleaner)
4345+
4346+ def work(self):
4347+ print 'Wednesday cleaning %s!' % self.context.name
4348+
4349+
4350+class SaturdayCleaner(grok.Subscription):
4351+ grok.implements(ICleaner)
4352+
4353+ def work(self):
4354+ print 'Saturday cleaning %s!' % self.context.name
4355+
4356
4357=== added file 'src/grokcore/component/tests/subscriptions/subscriptions_no_context.py'
4358--- src/grokcore/component/tests/subscriptions/subscriptions_no_context.py 1970-01-01 00:00:00 +0000
4359+++ src/grokcore/component/tests/subscriptions/subscriptions_no_context.py 2013-01-23 22:26:20 +0000
4360@@ -0,0 +1,20 @@
4361+"""
4362+ >>> grok.testing.grok(__name__)
4363+ Traceback (most recent call last):
4364+ ...
4365+ GrokError: No module-level context for
4366+ <class 'grokcore.component.tests.subscriptions.subscriptions_no_context.CaveProcessor'>,
4367+ please use the 'context' directive.
4368+
4369+"""
4370+
4371+import grokcore.component as grok
4372+from zope import interface
4373+
4374+class ITask(interface.Interface):
4375+
4376+ def finish():
4377+ pass
4378+
4379+class CaveProcessor(grok.Subscription):
4380+ grok.provides(ITask)
4381
4382=== added file 'src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py'
4383--- src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py 1970-01-01 00:00:00 +0000
4384+++ src/grokcore/component/tests/subscriptions/subscriptions_no_interface.py 2013-01-23 22:26:20 +0000
4385@@ -0,0 +1,17 @@
4386+"""
4387+ >>> grok.testing.grok(__name__)
4388+ Traceback (most recent call last):
4389+ ...
4390+ GrokError: <class 'grokcore.component.tests.subscriptions.subscriptions_no_interface.CaveProcessor'>
4391+ must implement at least one interface (use grok.implements to specify).
4392+
4393+"""
4394+
4395+import grokcore.component as grok
4396+
4397+
4398+class Cave(grok.Context):
4399+ pass
4400+
4401+class CaveProcessor(grok.Subscription):
4402+ pass
4403
4404=== modified file 'src/grokcore/component/tests/test_grok.py'
4405--- src/grokcore/component/tests/test_grok.py 2010-01-29 16:22:17 +0000
4406+++ src/grokcore/component/tests/test_grok.py 2013-01-23 22:26:20 +0000
4407@@ -1,7 +1,9 @@
4408 import re
4409-import unittest, traceback
4410+import unittest
4411+import traceback
4412+import doctest
4413 from pkg_resources import resource_listdir
4414-from zope.testing import doctest, cleanup, renormalizing
4415+from zope.testing import cleanup, renormalizing
4416 import zope.component.eventtesting
4417
4418 def setUpZope(test):
4419@@ -37,7 +39,7 @@
4420 checker=checker,
4421 optionflags=doctest.ELLIPSIS+
4422 doctest.NORMALIZE_WHITESPACE)
4423- except ImportError, e: # or should this accept anything?
4424+ except ImportError: # or should this accept anything?
4425 traceback.print_exc()
4426 raise
4427 suite.addTest(test)
4428@@ -46,7 +48,7 @@
4429 def test_suite():
4430 suite = unittest.TestSuite()
4431 for name in ['adapter', 'directive', 'grokker', 'utility', 'view',
4432- 'event', 'inherit']:
4433+ 'event', 'inherit', 'order', 'subscriptions']:
4434 suite.addTest(suiteFromPackage(name))
4435
4436 api = doctest.DocFileSuite('api.txt')
4437
4438=== added file 'src/grokcore/component/util.py'
4439--- src/grokcore/component/util.py 1970-01-01 00:00:00 +0000
4440+++ src/grokcore/component/util.py 2013-01-23 22:26:20 +0000
4441@@ -0,0 +1,143 @@
4442+##############################################################################
4443+#
4444+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
4445+# All Rights Reserved.
4446+#
4447+# This software is subject to the provisions of the Zope Public License,
4448+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
4449+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
4450+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
4451+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
4452+# FOR A PARTICULAR PURPOSE.
4453+#
4454+##############################################################################
4455+"""Grok utility functions.
4456+"""
4457+import types
4458+import zope.component.hooks
4459+from zope.interface.interfaces import IInterface
4460+from zope.interface import alsoProvides
4461+from grokcore.component import directive
4462+
4463+def _sort_key(component):
4464+ # If components have a grok.order directive, sort by that.
4465+ explicit_order, implicit_order = directive.order.bind().get(component)
4466+ return (explicit_order,
4467+ component.__module__,
4468+ implicit_order,
4469+ component.__class__.__name__)
4470+
4471+
4472+def sort_components(components, key=None):
4473+ """Sort a list of components using the information provided by
4474+ `grok.order`.
4475+ """
4476+ sort_key = _sort_key
4477+ if key is not None:
4478+ sort_key = lambda item: _sort_key(key(item))
4479+ return sorted(components, key=sort_key)
4480+
4481+
4482+def getSiteManager():
4483+ site = zope.component.hooks.getSite()
4484+ if site is None:
4485+ sm = zope.component.getGlobalSiteManager()
4486+ else:
4487+ sm = site.getSiteManager()
4488+ return sm
4489+
4490+
4491+def provideUtility(component, provides=None, name=u''):
4492+ sm = getSiteManager()
4493+ sm.registerUtility(component, provides, name, event=False)
4494+
4495+
4496+def provideAdapter(factory, adapts=None, provides=None, name=''):
4497+ sm = getSiteManager()
4498+ sm.registerAdapter(factory, adapts, provides, name, event=False)
4499+
4500+
4501+def provideSubscriptionAdapter(factory, adapts=None, provides=None):
4502+ sm = getSiteManager()
4503+ sm.registerSubscriptionAdapter(factory, adapts, provides, event=False)
4504+
4505+
4506+def provideHandler(factory, adapts=None):
4507+ sm = getSiteManager()
4508+ sm.registerHandler(factory, adapts, event=False)
4509+
4510+def provideInterface(id, interface, iface_type=None, info=''):
4511+ """register Interface with global site manager as utility
4512+
4513+ >>> gsm = zope.component.getGlobalSiteManager()
4514+
4515+ >>> from zope.interface import Interface
4516+ >>> from zope.interface.interfaces import IInterface
4517+ >>> from zope.component.tests import ITestType
4518+
4519+ >>> class I(Interface):
4520+ ... pass
4521+ >>> IInterface.providedBy(I)
4522+ True
4523+ >>> ITestType.providedBy(I)
4524+ False
4525+ >>> interfaces = gsm.getUtilitiesFor(ITestType)
4526+ >>> list(interfaces)
4527+ []
4528+
4529+ # provide first interface type
4530+ >>> provideInterface('', I, ITestType)
4531+ >>> ITestType.providedBy(I)
4532+ True
4533+ >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
4534+ >>> [name for (name, iface) in interfaces]
4535+ [u'zope.component.interface.I']
4536+ >>> [iface.__name__ for (name, iface) in interfaces]
4537+ ['I']
4538+
4539+ # provide second interface type
4540+ >>> class IOtherType(IInterface):
4541+ ... pass
4542+ >>> provideInterface('', I, IOtherType)
4543+
4544+ >>> ITestType.providedBy(I)
4545+ True
4546+ >>> IOtherType.providedBy(I)
4547+ True
4548+ >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
4549+ >>> [name for (name, iface) in interfaces]
4550+ [u'zope.component.interface.I']
4551+ >>> interfaces = list(gsm.getUtilitiesFor(IOtherType))
4552+ >>> [name for (name, iface) in interfaces]
4553+ [u'zope.component.interface.I']
4554+
4555+ >>> class I1(Interface):
4556+ ... pass
4557+ >>> provideInterface('', I1)
4558+ >>> IInterface.providedBy(I1)
4559+ True
4560+ >>> ITestType.providedBy(I1)
4561+ False
4562+ >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
4563+ >>> [name for (name, iface) in interfaces]
4564+ [u'zope.component.interface.I']
4565+ >>> [iface.__name__ for (name, iface) in interfaces]
4566+ ['I']
4567+ """
4568+ if not id:
4569+ id = "%s.%s" % (interface.__module__, interface.__name__)
4570+
4571+ if not IInterface.providedBy(interface):
4572+ if not isinstance(interface, (type, types.ClassType)):
4573+ raise TypeError(id, "is not an interface or class")
4574+ return
4575+
4576+ if iface_type is not None:
4577+ if not iface_type.extends(IInterface):
4578+ raise TypeError(iface_type, "is not an interface type")
4579+ alsoProvides(interface, iface_type)
4580+ else:
4581+ iface_type = IInterface
4582+
4583+ sm = getSiteManager()
4584+ sm.registerUtility(interface, iface_type, id, info)
4585
4586=== modified file 'src/grokcore/component/zcml.py'
4587--- src/grokcore/component/zcml.py 2010-01-29 16:22:17 +0000
4588+++ src/grokcore/component/zcml.py 2013-01-23 22:26:20 +0000
4589@@ -1,6 +1,6 @@
4590 ##############################################################################
4591 #
4592-# Copyright (c) 2006-2007 Zope Corporation and Contributors.
4593+# Copyright (c) 2006-2007 Zope Foundation and Contributors.
4594 # All Rights Reserved.
4595 #
4596 # This software is subject to the provisions of the Zope Public License,
4597@@ -15,11 +15,10 @@
4598
4599 from zope.interface import Interface
4600 from zope.configuration.fields import GlobalObject
4601-#from zope.configuration.config import ConfigurationMachine
4602+from zope.schema import TextLine
4603
4604 import martian
4605-#from martian import scan
4606-#from martian.error import GrokError
4607+
4608
4609 class IGrokDirective(Interface):
4610 """Grok a package or module."""
4611@@ -27,28 +26,46 @@
4612 package = GlobalObject(
4613 title=u"Package",
4614 description=u"The package or module to be analyzed by grok.",
4615- required=False,
4616- )
4617+ required=False)
4618+
4619+ exclude = TextLine(
4620+ title=u"Exclude",
4621+ description=u"Name to exclude in the grokking process.",
4622+ required=False)
4623+
4624
4625 # add a cleanup hook so that grok will bootstrap itself again whenever
4626 # the Component Architecture is torn down.
4627 def resetBootstrap():
4628 # we need to make sure that the grokker registry is clean again
4629 the_module_grokker.clear()
4630+
4631 from zope.testing.cleanup import addCleanUp
4632 addCleanUp(resetBootstrap)
4633
4634 the_multi_grokker = martian.MetaMultiGrokker()
4635 the_module_grokker = martian.ModuleGrokker(the_multi_grokker)
4636
4637+
4638 def skip_tests(name):
4639- return name in ['tests', 'ftests']
4640-
4641-def grokDirective(_context, package):
4642- do_grok(package.__name__, _context)
4643-
4644-def do_grok(dotted_name, config):
4645+ return name in ['tests', 'ftests', 'testing']
4646+
4647+
4648+def grokDirective(_context, package, exclude=None):
4649+ if not exclude:
4650+ exclude = None
4651+ do_grok(package.__name__, _context, extra_exclude=exclude)
4652+
4653+
4654+def do_grok(dotted_name, config, extra_exclude=None):
4655+ if extra_exclude is not None:
4656+
4657+ def exclude_filter(name):
4658+ return skip_tests(name) or extra_exclude == name
4659+
4660+ else:
4661+ exclude_filter = skip_tests
4662+
4663 martian.grok_dotted_name(
4664- dotted_name, the_module_grokker, exclude_filter=skip_tests,
4665- config=config
4666- )
4667+ dotted_name, the_module_grokker, exclude_filter=exclude_filter,
4668+ config=config)
4669
4670=== removed file 'versions.cfg'
4671--- versions.cfg 2010-01-29 16:22:17 +0000
4672+++ versions.cfg 1970-01-01 00:00:00 +0000
4673@@ -1,115 +0,0 @@
4674-# This is a copy of grok/versions.cfg revision 102959.
4675-#
4676-# Don't make local modifications here, just override it explicitly in
4677-# your buildout's [versions] part.
4678-
4679-[versions]
4680-ClientForm = 0.2.9
4681-grokcore.component = 1.7
4682-grokcore.formlib = 1.2
4683-grokcore.security = 1.1
4684-grokcore.view = 1.9
4685-grokcore.viewlet = 1.1
4686-grokui.admin = 0.3.2
4687-martian = 0.11
4688-mechanize = 0.1.7b
4689-pytz = 2007k
4690-RestrictedPython = 3.4.2
4691-simplejson = 1.7.1
4692-z3c.autoinclude = 0.2.2
4693-z3c.flashmessage = 1.0
4694-z3c.testsetup = 0.4
4695-zc.catalog = 1.2.0
4696-ZConfig = 2.5.1
4697-zc.recipe.testrunner = 1.0.0
4698-zdaemon = 2.0.2
4699-ZODB3 = 3.8.2
4700-zodbcode = 3.4.0
4701-zope.annotation = 3.4.1
4702-zope.app.apidoc = 3.4.3
4703-zope.app.applicationcontrol = 3.4.3
4704-zope.app.appsetup = 3.4.1
4705-zope.app.authentication = 3.4.4
4706-zope.app.basicskin = 3.4.0
4707-zope.app.broken = 3.4.0
4708-zope.app.catalog = 3.5.1
4709-zope.app.component = 3.4.1
4710-zope.app.container = 3.5.6
4711-zope.app.content = 3.4.0
4712-zope.app.debug = 3.4.1
4713-zope.app.dependable = 3.4.0
4714-zope.app.error = 3.5.1
4715-zope.app.exception = 3.4.1
4716-zope.app.file = 3.4.4
4717-zope.app.folder = 3.4.0
4718-zope.app.form = 3.4.1
4719-zope.app.generations = 3.4.1
4720-zope.app.http = 3.4.1
4721-zope.app.i18n = 3.4.4
4722-zope.app.interface = 3.4.0
4723-zope.app.intid = 3.4.1
4724-zope.app.keyreference = 3.4.1
4725-zope.app.locales = 3.4.5
4726-zope.app.onlinehelp = 3.4.1
4727-zope.app.pagetemplate = 3.4.1
4728-zope.app.preference = 3.4.1
4729-zope.app.principalannotation = 3.4.0
4730-zope.app.publication = 3.4.3
4731-zope.app.publisher = 3.5.1
4732-zope.app.renderer = 3.4.0
4733-zope.app.rotterdam = 3.4.1
4734-zope.app.schema = 3.4.0
4735-zope.app.security = 3.5.2
4736-zope.app.securitypolicy = 3.4.6
4737-zope.app.server = 3.4.2
4738-zope.app.session = 3.5.1
4739-zope.app.skins = 3.4.0
4740-zope.app.testing = 3.4.3
4741-zope.app.tree = 3.4.0
4742-zope.app.twisted = 3.4.1
4743-zope.app.wsgi = 3.4.1
4744-zope.app.zapi = 3.4.0
4745-zope.app.zcmlfiles = 3.4.3
4746-zope.app.zopeappgenerations = 3.4.0
4747-zope.cachedescriptors = 3.4.1
4748-zope.component = 3.4.0
4749-zope.configuration = 3.4.0
4750-zope.contentprovider = 3.4.0
4751-zope.contenttype = 3.4.0
4752-zope.copypastemove = 3.4.0
4753-zope.datetime = 3.4.0
4754-zope.deferredimport = 3.4.0
4755-zope.deprecation = 3.4.0
4756-zope.dottedname = 3.4.2
4757-zope.dublincore = 3.4.0
4758-zope.error = 3.5.1
4759-zope.event = 3.4.0
4760-zope.exceptions = 3.4.0
4761-zope.filerepresentation = 3.4.0
4762-zope.formlib = 3.4.0
4763-zope.hookable = 3.4.0
4764-zope.i18n = 3.4.0
4765-zope.i18nmessageid = 3.4.3
4766-zope.index = 3.4.1
4767-zope.interface = 3.4.1
4768-zope.lifecycleevent = 3.4.0
4769-zope.location = 3.4.0
4770-zope.minmax = 1.1.0
4771-zope.modulealias = 3.4.0
4772-zope.pagetemplate = 3.4.0
4773-zope.proxy = 3.4.2
4774-zope.publisher = 3.4.9
4775-zope.schema = 3.4.0
4776-zope.security = 3.4.1
4777-zope.securitypolicy = 3.4.1
4778-zope.server = 3.4.3
4779-zope.session = 3.4.1
4780-zope.size = 3.4.0
4781-zope.structuredtext = 3.4.0
4782-zope.tal = 3.4.1
4783-zope.tales = 3.4.0
4784-zope.testbrowser = 3.4.2
4785-zope.testing = 3.7.6
4786-zope.thread = 3.4
4787-zope.traversing = 3.4.1
4788-zope.viewlet = 3.4.2

Subscribers

People subscribed via source and target branches

to all changes: