Merge lp:~logan/ubuntu/raring/grokcore.component/2.5 into lp:ubuntu/raring/grokcore.component
- Raring (13.04)
- 2.5
- Merge into raring
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Holbach (community) | Approve | ||
Ubuntu branches | Pending | ||
Review via email:
|
Commit message
Description of the change
To post a comment you must log in.
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 |
Thanks. Uploaded.