[Zope-dev] Dependencies for ZCML

Martijn Faassen faassen at startifact.com
Thu Mar 12 12:42:11 EDT 2009


Chris McDonough wrote:
> Martijn Faassen wrote:
[snip]
>> Sometimes you can only test a library when a particular utility or 
>> adapter or event handler is registered. The library uses this utility or 
>> adapter in its own logic and while the utility or adapter is intended to 
>> be replaceable (to make the library pluggable), it is mandatory to 
>> actually register a component that fulfills the interface requirements 
>> in order to use the library at all.
> 
> Can you provide an example?  In my own libraries, very rarely does this happen;
> I tend to only depend on components like this "at the edges"; eg. in I only try
> to allow pluggability via the CA within an application or a framework, very
> rarely in a straight library.

Maybe because unlike you I don't know the difference between a framework 
and a library very well. :)

z3c.saconfig

Allows you to set up a utility that integrates with SQLAlchemy's scoped 
session so you can have one database configuration per Zope site. This 
is explicitly to support local configuration, but in order to use 
SQLAlchemy at all in this way the utility has got to be there in some form.

http://svn.zope.org/z3c.saconfig/trunk/

hurry.resource

Javascript/CSS resource management. Intended to be web-framework neutral.

Requires a utility ICurrentNeededInclusions to exist that somehow 
maintains the resource inclusions that are needed (for instance on the 
request object, but that's up to the utility).

Also needs a ILibraryUrl adapter to be defined on a resource in order to 
render the URL for a resource.

http://svn.zope.org/hurry.resource/trunk/

z3c.relationfield

A 'Relation' field for zope.schema that gets tracked by the zc.relation 
catalog.

Sets up a bunch of event handlers on IHasOutgoingRelations and 
IHasIncomingRelations. If you define those interfaces on your objects 
and use the Relation field in your schema, those relations are tracked.

http://svn.zope.org/z3c.relationfield/trunk

z3c.schema2xml

Exporting zope.schema-driven content as XML and importing XML into an 
object again. Offers a simple API to do this.

Registers a whole bunch of adapters for particular schema fields that 
know how to import and export attributes on objects that implement this 
schema.

http://svn.zope.org/z3c.schema2xml/trunk/

> But if somehow it does happen, and I need to test the library, and the library
> relies on some utility external to itself being registered, I'll register a
> "dummy" utility for purposes of testing.  I'll never use a "real" implementation
> of the component during *unit* testing (although during integration testing I'll
> use the real one instead of the dummy one of course).

Yes, I frequently do this, and frequently I load the ZCML (or grok 
things directly).

Anyway, we're not so interested in that distinction here, right? If the 
library does integration testing (testing the real component also 
defined by that library), this will need to be reflected in the 
dependencies just like anything else.

>> As a convenience to the users of this library, that library's 
>> configure.zcml will provide default implementations (which may be the 
>> right ones in most cases). This is a useful pattern.
> 
> Minor nit: the configure.zcml won't *provide* any default implementation, but
> might point at one.  This implementation may or may not live in the package that
> the configure.zcml lives in.

Sure, yes, it registers it. In case the case of grokked libraries, it 
provides *and* indicates the desire to do registration in the same place 
(typically the python class).

[snip]
> If some library comes along that thinks it knows enough to register mandatory
> arbitrary CA configuration, I'll classify it along with the Python stdlib
> "logging" module (which registers "atexit" handlers) or asyncore dispatchers
> (whose constructors register the dispatcher with a socket map); these libraries
> tend to be wrong about the configuration they register under some circumstance
> and it probably would have been better for their authors to do less, pushing the
> configuration more into some glue package or the application that uses them
> rather than down into the library itself.  That would offer maximum configurability.

This argument works for hurry.resource and z3c.saconfig, where people 
are expected to do their own registrations.

It doesn't work for z3c.relationfield:

If my library informs people that if they make their schema inherit 
IOutgoingRelations they can use Relation fields on it and any objects 
that implement that schema be tracked by a relation index automatically, 
I can't really say that the event handlers are somehow "wrong" and 
someone else would like to override them. People could hook up the event 
handlers again for their own interfaces, sure, but the original ones 
aren't in the way.

It also doesn't work for z3c.schema2xml:

The library's adapter registrations that know how to export a Text field 
aren't somehow in the way and it'd be a major pain to request people to 
reregister all these adapters themselves in an application. You can 
still override this registration just fine as well.

> In particular, I'm pretty sure that to be maximally useful outside a Zope
> context (which may or may not be desireable for the maintainer), library
> packages should probably be broken up into two pieces: a piece that is a
> straight Python library that contains no ZCML, then some "glue" package that
> provides both an API to use the library in a Zope context along with (possibly)
> some ZCML that is meant to be loaded by an application.

z3c.relationfield expects quite a few Zope-ish things to be around 
(containers, zc.relation), so it doesn't really have the goal to be 
useful outside a significantly non-Zope context.

z3c.schema2xml however is potentially very useful outside of a Zope 
context, and it'd be overkill to split it up into a straight Python 
library that contains no registrations and some glue package that then 
does the registrations. Its use of the configuration system makes sense, 
as you can easily plug into it to allow it to export other schema fields 
it may not know about.

[snip]
>> You're saying that we should be an include of the zope.component 
>> 'meta.zcml' in *all* ZCML files that register an adapter? This is 
>> certainly not happening always now. That's like import before usage in 
>> Python modules, right?
> 
> No.  He's saying that an application that makes use of some ZCML by inclusion
> from some package may need to load some metaconfiguration before the included
> file can be successfully used.

No. :) He said that any ZCML file which needs something like 
zope.component to be present should signal that by either including the 
meta.zcml of zope.component or by conditionally including it.

You're saying something else that fits the way ZCML has been in use from 
the start, but Tres expressed himself very badly if he said the same thing.

[snip]
>> So what does all of this mean for Dan's question? I don't know yet.
>>
>> I think we should observe some packages. We strive for library-like 
>> packages. More library-like packages should likely not have to do a lot 
>> of work in their configure.zcml, but the amount of work is not always 
>> zero.
> 
> I'll throw something out there: if a package *requires* configuration via ZCML
> to operate properly, I don't think it's really just a library (in the common
> Python sense).  Instead, I think its either a framework itself or some plugin to
> a framework.  OTOH, if it just offers up some default configuration that needn't
> be used to use the software, it might be a library.

Is this distinction useful in answering Dan's question?

In practice you could say that if the tests don't need the ZCML, then 
the ZCML dependencies (zope.configuration, zope.componentzcml) shouldn't 
be in the dependencies. If it does, they should be. :)

[snip my own analysis on whether the examples I gave above are libraries 
or frameworks or neither or both; it's a side-track]

Regards,

Martijn



More information about the Zope-Dev mailing list