Constrain versions of non-required packages

I have an add-on package which contains template overrides, e.g.:

<configure xmlns=""

Now it is clear that my template in the above example will override the equivalent template only for version 1.0.1 of the plone.batching package. I don't want the override to fail silently, so I put a plone.batching==1.0.1 constraint to the install_requires list of my package.

But I don't really require that plone.batching package; my package contains template overrides for several packages, and I just want my overrides to be effective when those packages are installed, and do nothing otherwise.

Is it possible to specify, "if package xy is installed, then require one of the supported versions"?

Yes, up to a certain degree it is possible:


As far as I know ptf acronym stands for program temporary patch.
What you want is probably some more permanent.

The official way of patching template in Plone is using z3c.jbot.

@jensens: Thanks for your answer; this ptf explanation is interesting.

I'm not yet sure I want something more permanent already; I'm currently splitting up my monolithic old-style Zope product to eggs, then I'll take on the migration of my Archetypes-based types to Dexterity and finally switch my Plone 4.3 site to Plone 5, probably directly to 5.1.

So what z3c.jbot allows me to do, is: inject templates (and images, etc.) into existing skin layers defined elsewhere, right? I do have my own skin layers already which I can use.

Here are my considerations, comments welcome:

If I'm sure my overridden templates will work for the whole range of possible package versions, I can use the z3c.jbot solution or my own skin layer; the latter has the advantage of unchanged filenames (handy for file comparisons), while in case of z3c.jbot the filenames contain the package names as well.

If I'm less sure, I could stick with the ptf solution.
Using that zcml:condition, I could create a .vcheck.mangled_package_name module for every optional package_name package which will be imported if the package_name package is present, and will raise a suitable exception if the version would not match my whitelist.
If this is the case, I'd check whether the overridden templates of that package have changed since the last version, and link my existing template to the new version as well (if unchanged) or create a new version of my override template which is suitable for the new version.

What is ptf? Configurations with hardcoded paths appear scary?!

@zopyx: Hi Andreas, I don't quite understand the intention of your comment yet.

What <ptf:patch> seems to allow me to do, is: Provide overrides which exactly match the package version of the overridden template.

  • If I'd simply apply my changes top the newest version of the supported range, I'd probably get errors when using older packages (which are pinned by older KGSs along the way), or need to insert error correction code.
  • If a newer version of a package arises, I might miss improvements from newer versions of that template without noticing.

The nature of the path specifications in the current_path attribute of the <ptf:patch> element deserves a closer look. Indeed they look like absolute file system paths, but I have never had an /eggs/ directory in my server roots.
For a package which aids code migration on a limited set of servers with similar setup, even absolute paths would look acceptable to me.

When my package complains about an unsupported package version, the procedure will be:

  • Compare the overridden templates from the supported package versions to the new version.
  • If identical to an already overridden version, reuse that override;
  • otherwise first copy the unchanged template of that new template, add it to version control, and then apply the local changes to this new override.

What is ptf:patch actually doing? Where is this coming from? Which package provides ptf:patch?

Good question. I found it in the project I inherited and simply continued to use it ...

However, I have a version constraining tool now. My (conditionally imported) checking modules look like so:

from import checkPathForPackage
checkPathForPackage('plone.batching', '1.0.1, 1.0.2')

By default, checkPathForPackage raises an exception if a non-whitelisted package version is found (which is what I want), or if the package is not found in sys.path (which is prevented by a conditional import, but could be overridden by using the missing option). That buildout module is contained in v1.2.2.dev1+.