[Grok-dev] Grok actions and grok.grok() cleanup

Philipp von Weitershausen philipp at weitershausen.de
Sat Oct 13 08:16:21 EDT 2007

Godefroid started converting grokkers to emit configuration actions as
known from ZCML. The work is on the gotcha-configuration-actions branch.
The advantages of emitting actions, among others, are that you'll get
conflicts trying to register the same things twice and you can override
components using zope.configuration's override mechanism.

I've finished this work now. This impact for your code is very little to
none. If you use grok.grok() in your unit tests, you will have to use
grok.tests.grok() so that the configuration actions are executed. I will
probalby move this to grok.testing.grok() though. grok_component will
likely also move to grok.testing (if Martijn and other people who use it
are ok with that).

At the same time, I've also cleaned up grok.grok() to ease the
long-planned split-up of Grok into reusable bits. Specifically, I've
gotten rid of the prepare and finalize function that are run before and
after grokking each module.

The prepare method's job is to insert new keyword arguments to grokkers.
This essentially makes all the grokkers dependent on this particular
prepare function, therefore making the split-up impossible. Here's how I
tackled the individual keyword-arguments:

* module_info: Since this is generally useful for all grokkers, I've
created a branch of martian that now always passes it in as a keyword
argument. This change is completely backwards compatible because a) most
grokkers took the module_info argument in the first place and b)
grokkers are required by the IGrokker interface to take **kw anyway. So
even if they wouldn't wanted module_info, it wouldn't matter.

* context: This is the object that is figured out by scanning for
grok.Model and grok.Container subclasses. I now implemented a global
(=module) grokker that has a higher priority than all the other
grokkers, therefore it's executed ahead of them. It does the scanning
and save the result in module.__grok_context__. This is incidentally the
same variable that the module-level grok.context() directive uses. So
module.__grok_context__ either contains the explicitly set context or it
will contain the implicitly figured-out context (or it will contain the
special AMBIGUOUS_CONTEXT marker which leads to an error). The advantage
of this being a grokker also means it's now pluggable which classes are
treated as implicit contexts.

* templates: This is now also dealt with by a grokker that creates the
templates registry and puts it into modules.__grok_templates__. Grokkers
that need it can get it using
module_info.getAnnotation('grok.templates'), just like we get all other
module-related annotations.

The finalize method basically checked for unassociated tempates and
raises an error if it found any. I've turned this into a grokker as well
and gave it a very low priority (-1000) so it's executed after all other

To summarize the visible changes for 3rd party code:

* grok.grok() changed because of the configuration action dependency.
Use grok.tests.grok() (or wherever it will finally move) instead.

* Grokkers get a new 'config' keyword argument which is the
zope.configuration context. It's the object you should use to emit actions.

* Grokkers no longer get 'context' and 'templates' as arguments. Use
module_info.getAnnotation('grok.context') or 'grok.templates' instead.

Since I encountered a few grokker implementations that weren't accepting
  **kw, I'd like to reiterate that the IGrokker interface demands this
(especially since prepare and finalize functions can pass in more
arbitrary parameters). So if you have custom grokkers, make sure they
take at least **kw.

I'd like to get this branch merged in a timely fashion.

http://worldcookery.com -- Professional Zope documentation and training

More information about the Grok-dev mailing list