Egg Recipe API for other Recipes

It is common for recipes to accept a collection of egg specifications and generate scripts based on the resulting working sets. The egg recipe provides an API that other recipes can use.

A recipe can reuse the egg recipe, supporting the eggs, find-links, index, and extra-paths options. This is done by creating an egg recipe instance in a recipes’s constructor. In the recipe’s install script, the egg-recipe instance’s working_set method is used to collect the requested eggs and working set.

To illustrate, we create a sample recipe that is a very thin layer around the egg recipe:

>>> mkdir(sample_buildout, 'sample')
>>> write(sample_buildout, 'sample', 'sample.py',
... """
... import logging, os, sys
... import zc.recipe.egg
...
... def print_(*args):
...     sys.stdout.write(' '.join(map(str, args)) + '\\n')
...
... class Sample:
...
...     def __init__(self, buildout, name, options):
...         self.egg = zc.recipe.egg.Scripts(buildout, name, options)
...         self.name = name
...         self.options = options
...
...     def install(self):
...         extras = self.options['extras'].split()
...         requirements, ws = self.egg.working_set(extras)
...         print_('Part:', self.name)
...         print_('Egg requirements:')
...         for r in requirements:
...             print_(r)
...         print_('Working set:')
...         for d in ws:
...             print_(d)
...         print_('extra paths:', self.egg.extra_paths)
...         return ()
...
...     update = install
... """)

Here we instantiated the egg recipe in the constructor, saving it in an attribute. This also initialized the options dictionary.

In our install method, we called the working_set method on the instance we saved. The working_set method takes an optional sequence of extra requirements to be included in the working set.

>>> write(sample_buildout, 'sample', 'setup.py',
... """
... from setuptools import setup
...
... setup(
...     name = "sample",
...     entry_points = {'zc.buildout': ['default = sample:Sample']},
...     install_requires = 'zc.recipe.egg',
...     )
... """)
>>> write(sample_buildout, 'sample', 'README.txt', " ")
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = sample
... parts = sample-part
...
... [sample-part]
... recipe = sample
... eggs = demo<0.3
... find-links = %(server)s
... index = %(server)sindex
... extras = other
... """ % dict(server=link_server))
>>> import os
>>> os.chdir(sample_buildout)
>>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
>>> print_(system(buildout + ' -q'), end='')
Part: sample-part
Egg requirements:
demo<0.3
Working set:
demo 0.2
other 1.0
demoneeded 1.1
extra paths: []

We can see that the options were augmented with additional data computed by the egg recipe by looking at .installed.cfg:

>>> cat(sample_buildout, '.installed.cfg')
[buildout]
installed_develop_eggs = /sample-buildout/develop-eggs/sample.egg-link
parts = sample-part

[sample-part]
__buildout_installed__ =
__buildout_signature__ = sample-6aWMvV2EJ9Ijq+bR8ugArQ==
        zc.recipe.egg-cAsnudgkduAa/Fd+WJIM6Q==
        distribute-0.6-py2.4.egg
        zc.buildout-+rYeCcmFuD1K/aB77XTj5A==
_b = /sample-buildout/bin
_d = /sample-buildout/develop-eggs
_e = /sample-buildout/eggs
bin-directory = /sample-buildout/bin
develop-eggs-directory = /sample-buildout/develop-eggs
eggs = demo<0.3
eggs-directory = /sample-buildout/eggs
extras = other
find-links = http://localhost:27071/
index = http://localhost:27071/index
recipe = sample

If we use the extra-paths option:

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = sample
... parts = sample-part
...
... [sample-part]
... recipe = sample
... eggs = demo<0.3
... find-links = %(server)s
... index = %(server)sindex
... extras = other
... extra-paths = /foo/bar
...               /spam/eggs
... """ % dict(server=link_server))

Then we’ll see that reflected in the extra_paths attribute in the egg recipe instance:

>>> print_(system(buildout + ' -q'), end='')
Part: sample-part
Egg requirements:
demo<0.3
Working set:
demo 0.2
other 1.0
demoneeded 1.1
extra paths: ['/foo/bar', '/spam/eggs']