Packages should load configuration they depend upon

Author: Philipp von Weitershausen
Version: 1.0
Last Changed:2007-11-09

Summary and current situation

When we "exploded" Zope into individual eggs, we introduced explicit package dependencies in setup.py. This allows us to install a package indepedently and still ensure that its dependencies are installed as well.

Packages not only depend on other Python packages because they want to import their components, however. They often also depend on those package's configuration. Therefore, in order to be able to run the functional tests of each package, we introduced functional test layers for each package which load the necessary configuration.

The following proposal outlines why not the functional test layer should load the configuration that the package depends on, but the package itself.

Problem

Let's say you want to use any package that requires more configuration than it currently loads. A good example is zope.app.apidoc. You can't simply say:

<include package="zope.app.apidoc" />

Instead, you'll have to include the configuration of all its dependencies first:

<include package="zope.app.zcmlfiles" file="meta.zcml" />
<include package="zope.app.preference" file="meta.zcml" />
<include package="zope.app.onlinehelp" file="meta.zcml" />
<include package="zope.app.apidoc" file="meta.zcml" />

<include package="zope.app.zcmlfiles" />
<include package="zope.app.tree" />
<include package="zope.app.onlinehelp" />
<include package="zope.app.renderer" />
<include package="zope.app.preference" />
<include package="zope.app.apidoc" />

Proposed solution

For each package, move the include statements that are intrinsic to the package's dependencies from ftesting.zcml to configure.zcml. For instance, zope.app.apidoc/configure.zcml would start off like this:

<configure>
  <include package="zope.app.zcmlfiles" file="meta.zcml" />
  <include package="zope.app.preference" file="meta.zcml" />
  <include package="zope.app.onlinehelp" file="meta.zcml" />
  <include file="meta.zcml" />

  <include package="zope.app.zcmlfiles" />
  <include package="zope.app.tree" />
  <include package="zope.app.onlinehelp" />
  <include package="zope.app.renderer" />
  <include package="zope.app.preference" />

Then, if you wanted to enable APIDoc? in your application, you could simply do:

<include package="zope.app.apidoc" />

Risks

You might want to load a package's configuration without loading the configuration that the package depends on, for instance because you want to supply a different set of components/directives. This can still be achieved with the proposed model by using the exclusion mechanism provided by zc.configuration.

Not a risk: Since most packages share common requirements regarding the configuration they depend on (e.g. the meta directives that register the browser directives), some ZCML files will likely be included multiple times. This is not a problem though because ZCML will only execute the file the first time and then ignore subsequent includes.

... --Chris McDonough?, Fri, 09 Nov 2007 19:04:06 +0000 reply

This is besides the point, but I don't believe a package's "install_requires" should name packages that are depended upon only by the ZCML in another package (ie. if nothing is Python-imported from these packages) unless these dependencies are named as extras. Other than that I'm neutral.

... --wichert, Fri, 09 Nov 2007 19:12:29 +0000 reply

With this proposal you are duplicating the dependencies on two places: setup.py and configure.zcml. Note that you may possibly need to do the same thing for meta.zcml and overrides.zcml as well.

I would prefer to using zcml entry points in eggs and a zcml statement to load those.

... --FredDrake?, Fri, 09 Nov 2007 19:22:02 +0000 reply

I'm envisioning a day when I won't be able to re-use any ZCML since it'll force me to pick up lots of junk I don't want.

I hope we're able to develop some better practices for handling ZCML than we have now, because it's a mess.

... --Chris McDonough?, Fri, 09 Nov 2007 19:24:45 +0000 reply

wiggy: the dependencies need to be duplicated (or at least need to differ) if you just want to use the egg for its "librariness" (if you're unconcerned about loading any of its zcml). That said, I actually think in a perfect world, no one would attempt to use packages that have ZCML in them as a plain-old Python library. Instead, each package that wanted to be used as a library would be separated out into two packages: one with the just the library code, the other containing the Zope 3 "bindings" in the form of ZCML and zcml.py, etc. Then the install_requires setup.py of the "bindings" packages could depend on the library as well as any other bindings package its ZCML considers a dependency.

... --srichter, Mon, 12 Nov 2007 00:21:49 +0000 reply

I have to think about this for a while. I definitely understand your motivation and I think it is a good one. But I have not convinced myself yet, that there are no other negative side-effects.

The least we should do is to list the dependency ZCML files in a "dependencies.zcml" file.



( 98 subscribers )