Python API for egg and script installation ========================================== The easy_install module provides some functions to provide support for egg and script installation. It provides functionality at the python level that is similar to easy_install, with a few exceptions: - By default, we look for new packages *and* the packages that they depend on. This is somewhat like (and uses) the --upgrade option of easy_install, except that we also upgrade required packages. - If the highest-revision package satisfying a specification is already present, then we don't try to get another one. This saves a lot of search time in the common case that packages are pegged to specific versions. - If there is a develop egg that satisfies a requirement, we don't look for additional distributions. We always give preference to develop eggs. - Distutils options for building extensions can be passed. Distribution installation ------------------------- The easy_install module provides a function, install, for installing one or more packages and their dependencies. The install function takes 2 positional arguments: - An iterable of setuptools requirement strings for the distributions to be installed, and - A destination directory to install to and to satisfy requirements from. The destination directory can be None, in which case, no new distributions are downloaded and there will be an error if the needed distributions can't be found amoung those already installed. It supports a number of optional keyword arguments: find-links A sequence of URLs, file names, or directories to look for links to distributions. index The URL of an index server, or almost any other valid URL. :) If not specified, the Python Package Index, http://cheeseshop.python.org/pypi, is used. You can specify an alternate index with this option. If you use the links option and if the links point to the needed distributions, then the index can be anything and will be largely ignored. In the examples, here, we'll just point to an empty directory on our link server. This will make our examples run a little bit faster. executable A path to a Python executable. Distributions will ne installed using this executable and will be for the matching Python version. path A list of additional directories to search for locally-installed distributions. always_unzip A flag indicating that newly-downloaded distributions should be directories even if they could be installed as zip files. working_set An exsiting working set to be augmented with additional distributions, if necessary to satisfy requirements. This allows you to call install multiple times, if necessary, to gather multiple sets of requirements. newest A boolian value indicating whether to search for new distributions when already-installed distributions meet the requirement. When this is true, the default, and when the destination directory is not None, then the install function will search for the newest distributions that satisfy the requirements. versions A dictionary mapping project names to version numbers to be used when selecting distributions. This can be used to specify a set of distribution versions independent of other requirements. The install method returns a working set containing the distributions needed to meet the given requirements. We have a link server that has a number of eggs: >>> print get(link_server), <html><body> <a href="demo-0.1-py2.4.egg">demo-0.1-py2.4.egg</a><br> <a href="demo-0.2-py2.4.egg">demo-0.2-py2.4.egg</a><br> <a href="demo-0.3-py2.4.egg">demo-0.3-py2.4.egg</a><br> <a href="demoneeded-1.0.zip">demoneeded-1.0.zip</a><br> <a href="demoneeded-1.1.zip">demoneeded-1.1.zip</a><br> <a href="extdemo-1.4.zip">extdemo-1.4.zip</a><br> <a href="index/">index/</a><br> <a href="other-1.0-py2.4.egg">other-1.0-py2.4.egg</a><br> </body></html> Let's make a directory and install the demo egg to it, using the demo: >>> dest = tmpdir('sample-install') >>> import zc.buildout.easy_install >>> ws = zc.buildout.easy_install.install( ... ['demo==0.2'], dest, ... links=[link_server], index=link_server+'index/') We requested version 0.2 of the demo distribution to be installed into the destination server. We specified that we should search for links on the link server and that we should use the (empty) link server index directory as a package index. The working set contains the distributions we retrieved. >>> for dist in ws: ... print dist demo 0.2 demoneeded 1.1 And the actual eggs were added to the eggs directory. >>> ls(dest) - demo-0.2-py2.4.egg - demoneeded-1.1-py2.4.egg If we remove the version restriction on demo, but specify a false value for newest, no new didstributions will be installed: >>> ws = zc.buildout.easy_install.install( ... ['demo'], dest, links=[link_server], index=link_server+'index/', ... newest=False) >>> ls(dest) - demo-0.2-py2.4.egg - demoneeded-1.1-py2.4.egg If we leave off the newst option, we'll get an update for demo: >>> ws = zc.buildout.easy_install.install( ... ['demo'], dest, links=[link_server], index=link_server+'index/') >>> ls(dest) - demo-0.2-py2.4.egg - demo-0.3-py2.4.egg - demoneeded-1.1-py2.4.egg We can supply additional distributions. We can also supply specifications for distributions that would normally be found via dependencies. We might do this to specify a sprcific version. >>> ws = zc.buildout.easy_install.install( ... ['demo', 'other', 'demoneeded==1.0'], dest, ... links=[link_server], index=link_server+'index/') >>> for dist in ws: ... print dist demo 0.3 other 1.0 demoneeded 1.0 >>> ls(dest) - demo-0.2-py2.4.egg - demo-0.3-py2.4.egg - demoneeded-1.0-py2.4.egg - demoneeded-1.1-py2.4.egg d other-1.0-py2.4.egg We can request that eggs be unzipped even if they are zip safe. This can be useful when debugging. >>> rmdir(dest) >>> dest = tmpdir('sample-install') >>> ws = zc.buildout.easy_install.install( ... ['demo'], dest, links=[link_server], index=link_server+'index/', ... always_unzip=True) >>> ls(dest) d demo-0.3-py2.4.egg d demoneeded-1.1-py2.4.egg >>> rmdir(dest) >>> dest = tmpdir('sample-install') >>> ws = zc.buildout.easy_install.install( ... ['demo'], dest, links=[link_server], index=link_server+'index/', ... always_unzip=True) >>> ls(dest) d demo-0.3-py2.4.egg d demoneeded-1.1-py2.4.egg Specifying version information indepenent of requirements --------------------------------------------------------- Sometimes it's useful to specify version information indepenent of normal requirements specifications. For example, a buildout may need to lock down a set of versions, without having to put put version numbers in setup files or part definitions. If a dictionary is passed to the install function, mapping project names to version numbers, then the versions numbers will be used. >>> ws = zc.buildout.easy_install.install( ... ['demo'], dest, links=[link_server], index=link_server+'index/', ... versions = dict(demo='0.2', demoneeded='1.0')) >>> [d.version for d in ws] ['0.2', '1.0'] In this example, we specified a version for demoneeded, even though we didn't define a requirement for it. The versions specified apply to depenencies as well as the specified requirements. If we specify a version that's incompatible with a requirement, then we'll get an error: >>> from zope.testing.loggingsupport import InstalledHandler >>> handler = InstalledHandler('zc.buildout.easy_install') >>> import logging >>> logging.getLogger('zc.buildout.easy_install').propagate = False >>> ws = zc.buildout.easy_install.install( ... ['demo >0.2'], dest, links=[link_server], ... index=link_server+'index/', ... versions = dict(demo='0.2', demoneeded='1.0')) Traceback (most recent call last): ... IncompatibleVersionError: Bad version 0.2 >>> print handler zc.buildout.easy_install DEBUG Installing ['demo >0.2'] zc.buildout.easy_install ERROR The version, 0.2, is not consistent with the requirement, demo>0.2 >>> handler.clear() If no versions are specified, a debugging message will be output reporting that a version was picked automatically: >>> ws = zc.buildout.easy_install.install( ... ['demo'], dest, links=[link_server], index=link_server+'index/', ... ) >>> print handler zc.buildout.easy_install DEBUG Installing ['demo'] zc.buildout.easy_install DEBUG We have the best distribution that satisfies demo zc.buildout.easy_install.picked DEBUG demo = 0.3 zc.buildout.easy_install DEBUG Getting required demoneeded zc.buildout.easy_install DEBUG We have the best distribution that satisfies demoneeded zc.buildout.easy_install.picked DEBUG demoneeded = 1.1 >>> handler.uninstall() >>> logging.getLogger('zc.buildout.easy_install').propagate = True The function default_versions can be used to get and set default version information to be used when no version information is passes. If called with an argument, it sets the default versions: >>> zc.buildout.easy_install.default_versions(dict(demoneeded='1')) {} It always returns the previous default versions. If called without an argument, it simply returns the default versions without changing them: >>> zc.buildout.easy_install.default_versions() {'demoneeded': '1'} So with the default versions set, we'll get the requested version even if the versions option isn't used: >>> ws = zc.buildout.easy_install.install( ... ['demo'], dest, links=[link_server], index=link_server+'index/', ... ) >>> [d.version for d in ws] ['0.3', '1.0'] Of course, we can unset the default versions by passing an empty dictionary: >>> zc.buildout.easy_install.default_versions({}) {'demoneeded': '1'} >>> ws = zc.buildout.easy_install.install( ... ['demo'], dest, links=[link_server], index=link_server+'index/', ... ) >>> [d.version for d in ws] ['0.3', '1.1'] Script generation ----------------- The easy_install module provides support for creating scripts from eggs. It provides a function similar to setuptools except that it provides facilities for baking a script's path into the script. This has two advantages: - The eggs to be used by a script are not chosen at run time, making startup faster and, more importantly, deterministic. - The script doesn't have to import pkg_resources because the logic that pkg_resources would execute at run time is executed at script-creation time. The scripts method can be used to generate scripts. Let's create a destination directory for it to place them in: >>> import tempfile >>> bin = tmpdir('bin') Now, we'll use the scripts method to generate scripts in this directory from the demo egg: >>> import sys >>> scripts = zc.buildout.easy_install.scripts( ... ['demo'], ws, sys.executable, bin) the four arguments we passed were: 1. A sequence of distribution requirements. These are of the same form as setuptools requirements. Here we passed a single requirement, for the version 0.1 demo distribution. 2. A working set, 3. The Python executable to use, and 3. The destination directory. The bin directory now contains a generated script: >>> ls(bin) - demo The return value is a list of the scripts generated: >>> import os, sys >>> if sys.platform == 'win32': ... scripts == [os.path.join(bin, 'demo.exe'), ... os.path.join(bin, 'demo-script.py')] ... else: ... scripts == [os.path.join(bin, 'demo')] True Note that in Windows, 2 files are generated for each script. A script file, ending in '-script.py', and an exe file that allows the script to be invoked directly without having to specify the Python interpreter and without having to provide a '.py' suffix. The demo script run the entry point defined in the demo egg: >>> cat(bin, 'demo') # doctest: +NORMALIZE_WHITESPACE #!/usr/local/bin/python2.4 <BLANKLINE> import sys sys.path[0:0] = [ '/sample-install/demo-0.3-py2.4.egg', '/sample-install/demoneeded-1.1-py2.4.egg', ] <BLANKLINE> import eggrecipedemo <BLANKLINE> if __name__ == '__main__': eggrecipedemo.main() Some things to note: - The demo and demoneeded eggs are added to the beginning of sys.path. - The module for the script entry point is imported and the entry point, in this case, 'main', is run. Rather than requirement strings, you can pass tuples containing 3 strings: - A script name, - A module, - An attribute expression for an entry point within the module. For example, we could have passed antry point information directly rather than passing a requirement: >>> scripts = zc.buildout.easy_install.scripts( ... [('demo', 'eggrecipedemo', 'main')], ... ws, sys.executable, bin) >>> cat(bin, 'demo') # doctest: +NORMALIZE_WHITESPACE #!/usr/local/bin/python2.4 <BLANKLINE> import sys sys.path[0:0] = [ '/sample-install/demo-0.3-py2.4.egg', '/sample-install/demoneeded-1.1-py2.4.egg', ] <BLANKLINE> import eggrecipedemo <BLANKLINE> if __name__ == '__main__': eggrecipedemo.main() Passing entry-point information directly is handy when using eggs (or distributions) that don't declare their entry points, such as distributions that aren't based on setuptools. The interpreter keyword argument can be used to generate a script that can be used to invoke the Python interactive interpreter with the path set based on the working set. This generated script can also be used to run other scripts with the path set on the working set: >>> scripts = zc.buildout.easy_install.scripts( ... ['demo'], ws, sys.executable, bin, interpreter='py') >>> ls(bin) - demo - py >>> if sys.platform == 'win32': ... scripts == [os.path.join(bin, 'demo.exe'), ... os.path.join(bin, 'demo-script.py'), ... os.path.join(bin, 'py.exe'), ... os.path.join(bin, 'py-script.py')] ... else: ... scripts == [os.path.join(bin, 'demo'), ... os.path.join(bin, 'py')] True The py script simply runs the Python interactive interpreter with the path set: >>> cat(bin, 'py') # doctest: +NORMALIZE_WHITESPACE #!/usr/local/bin/python2.4 import sys <BLANKLINE> sys.path[0:0] = [ '/sample-install/demo-0.3-py2.4.egg', '/sample-install/demoneeded-1.1-py2.4.egg', ] <BLANKLINE> _interactive = True if len(sys.argv) > 1: import getopt _options, _args = getopt.getopt(sys.argv[1:], 'ic:') _interactive = False for (_opt, _val) in _options: if _opt == '-i': _interactive = True elif _opt == '-c': exec _val <BLANKLINE> if _args: sys.argv[:] = _args execfile(sys.argv[0]) <BLANKLINE> if _interactive: import code code.interact(banner="", local=globals()) If invoked with a script name and arguments, it will run that script, instead. An additional argumnet can be passed to define which scripts to install and to provide script names. The argument is a dictionary mapping original script names to new script names. >>> bin = tmpdir('bin2') >>> scripts = zc.buildout.easy_install.scripts( ... ['demo'], ws, sys.executable, bin, dict(demo='run')) >>> if sys.platform == 'win32': ... scripts == [os.path.join(bin, 'run.exe'), ... os.path.join(bin, 'run-script.py')] ... else: ... scripts == [os.path.join(bin, 'run')] True >>> ls(bin) - run >>> print system(os.path.join(bin, 'run')), 3 1 Including extra paths in scripts -------------------------------- We can pass a keyword argument, extra paths, to caue additional paths to be included in the a generated script: >>> scripts = zc.buildout.easy_install.scripts( ... ['demo'], ws, sys.executable, bin, dict(demo='run'), ... extra_paths=['/foo/bar']) >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE #!/usr/local/bin/python2.4 <BLANKLINE> import sys sys.path[0:0] = [ '/sample-install/demo-0.3-py2.4.egg', '/sample-install/demoneeded-1.1-py2.4.egg', '/foo/bar', ] <BLANKLINE> import eggrecipedemo <BLANKLINE> if __name__ == '__main__': eggrecipedemo.main() Providing script arguments -------------------------- An "argument" keyword argument can be used to pass arguments to an entry point. The value passed is a source string to be placed between the parentheses in the call: >>> scripts = zc.buildout.easy_install.scripts( ... ['demo'], ws, sys.executable, bin, dict(demo='run'), ... arguments='1, 2') >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE #!/usr/local/bin/python2.4 import sys sys.path[0:0] = [ '/sample-install/demo-0.3-py2.4.egg', '/sample-install/demoneeded-1.1-py2.4.egg', ] <BLANKLINE> import eggrecipedemo <BLANKLINE> if __name__ == '__main__': eggrecipedemo.main(1, 2) Passing initialization code --------------------------- You can also pass script initialization code: >>> scripts = zc.buildout.easy_install.scripts( ... ['demo'], ws, sys.executable, bin, dict(demo='run'), ... arguments='1, 2', ... initialization='import os\nos.chdir("foo")') >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE #!/usr/local/bin/python2.4 import sys sys.path[0:0] = [ '/sample-install/demo-0.3-py2.4.egg', '/sample-install/demoneeded-1.1-py2.4.egg', ] <BLANKLINE> import os os.chdir("foo") <BLANKLINE> import eggrecipedemo <BLANKLINE> if __name__ == '__main__': eggrecipedemo.main(1, 2) Handling custom build options for extensions provided in source distributions ----------------------------------------------------------------------------- Sometimes, we need to control how extension modules are built. The build function provides this level of control. It takes a single package specification, downloads a source distribution, and builds it with specified custom build options. The build function takes 3 positional arguments: spec A package specification for a source distribution dest A destination directory build_ext A dictionary of options to be passed to the distutils build_ext command when building extensions. It supports a number of optional keyword arguments: links a sequence of URLs, file names, or directories to look for links to distributions, index The URL of an index server, or almost any other valid URL. :) If not specified, the Python Package Index, http://cheeseshop.python.org/pypi, is used. You can specify an alternate index with this option. If you use the links option and if the links point to the needed distributions, then the index can be anything and will be largely ignored. In the examples, here, we'll just point to an empty directory on our link server. This will make our examples run a little bit faster. executable A path to a Python executable. Distributions will ne installed using this executable and will be for the matching Python version. path A list of additional directories to search for locally-installed distributions. newest A boolian value indicating whether to search for new distributions when already-installed distributions meet the requirement. When this is true, the default, and when the destination directory is not None, then the install function will search for the newest distributions that satisfy the requirements. versions A dictionary mapping project names to version numbers to be used when selecting distributions. This can be used to specify a set of distribution versions independent of other requirements. Our link server included a source distribution that includes a simple extension, extdemo.c:: #include <Python.h> #include <extdemo.h> static PyMethodDef methods[] = {}; PyMODINIT_FUNC initextdemo(void) { PyObject *m; m = Py_InitModule3("extdemo", methods, ""); #ifdef TWO PyModule_AddObject(m, "val", PyInt_FromLong(2)); #else PyModule_AddObject(m, "val", PyInt_FromLong(EXTDEMO)); #endif } The extension depends on a system-dependent include file, extdemo.h, that defines a constant, EXTDEMO, that is exposed by the extension. We'll add an include directory to our sample buildout and add the needed include file to it: >>> mkdir('include') >>> write('include', 'extdemo.h', ... """ ... #define EXTDEMO 42 ... """) Now, we can use the build function to create an egg from the source distribution: >>> zc.buildout.easy_install.build( ... 'extdemo', dest, ... {'include-dirs': os.path.join(sample_buildout, 'include')}, ... links=[link_server], index=link_server+'index/') ['/sample-install/extdemo-1.4-py2.4-unix-i686.egg'] The function returns the list of eggs Now if we look in our destination directory, we see we have an extdemo egg: >>> ls(dest) - demo-0.2-py2.4.egg d demo-0.3-py2.4.egg - demoneeded-1.0-py2.4.egg d demoneeded-1.1-py2.4.egg d extdemo-1.4-py2.4-unix-i686.egg Let's update our link server with a new version of extdemo: >>> update_extdemo() >>> print get(link_server), <html><body> <a href="demo-0.1-py2.4.egg">demo-0.1-py2.4.egg</a><br> <a href="demo-0.2-py2.4.egg">demo-0.2-py2.4.egg</a><br> <a href="demo-0.3-py2.4.egg">demo-0.3-py2.4.egg</a><br> <a href="demoneeded-1.0.zip">demoneeded-1.0.zip</a><br> <a href="demoneeded-1.1.zip">demoneeded-1.1.zip</a><br> <a href="extdemo-1.4.zip">extdemo-1.4.zip</a><br> <a href="extdemo-1.5.zip">extdemo-1.5.zip</a><br> <a href="index/">index/</a><br> <a href="other-1.0-py2.4.egg">other-1.0-py2.4.egg</a><br> </body></html> The easy_install caches information about servers to reduce network access. To see the update, we have to call the clear_index_cache function to clear the index cache: >>> zc.buildout.easy_install.clear_index_cache() If we run build with newest set to False, we won't get an update: >>> zc.buildout.easy_install.build( ... 'extdemo', dest, ... {'include-dirs': os.path.join(sample_buildout, 'include')}, ... links=[link_server], index=link_server+'index/', ... newest=False) ['/sample-install/extdemo-1.4-py2.4-linux-i686.egg'] >>> ls(dest) - demo-0.2-py2.4.egg d demo-0.3-py2.4.egg - demoneeded-1.0-py2.4.egg d demoneeded-1.1-py2.4.egg d extdemo-1.4-py2.4-unix-i686.egg But if we run it with the default True setting for newest, then we'll get an updated egg: >>> zc.buildout.easy_install.build( ... 'extdemo', dest, ... {'include-dirs': os.path.join(sample_buildout, 'include')}, ... links=[link_server], index=link_server+'index/') ['/sample-install/extdemo-1.5-py2.4-unix-i686.egg'] >>> ls(dest) - demo-0.2-py2.4.egg d demo-0.3-py2.4.egg - demoneeded-1.0-py2.4.egg d demoneeded-1.1-py2.4.egg d extdemo-1.4-py2.4-unix-i686.egg d extdemo-1.5-py2.4-unix-i686.egg The versions option also influences the versions used. For example, if we specify a version for extdemo, then that will be used, even though it isn't the newest. Let's clean out the destimation directory first: >>> import os >>> for name in os.listdir(dest): ... remove(dest, name) >>> zc.buildout.easy_install.build( ... 'extdemo', dest, ... {'include-dirs': os.path.join(sample_buildout, 'include')}, ... links=[link_server], index=link_server+'index/', ... versions=dict(extdemo='1.4')) ['/sample-install/extdemo-1.4-py2.4-unix-i686.egg'] >>> ls(dest) d extdemo-1.4-py2.4-unix-i686.egg Handling custom build options for extensions in develop eggs ------------------------------------------------------------ The develop function is similar to the build function, except that, rather than building an egg from a source directory containing a setup.py script. The develop function takes 2 positional arguments: setup The path to a setup script, typically named "setup.py", or a directory containing a setup.py script. dest The directory to install the egg link to It supports some optional keyword argument: build_ext A dictionary of options to be passed to the distutils build_ext command when building extensions. executable A path to a Python executable. Distributions will ne installed using this executable and will be for the matching Python version. We have a local directory containing the extdemo source: >>> ls(extdemo) - MANIFEST - MANIFEST.in - README - extdemo.c - setup.py Now, we can use the develop function to create a develop egg from the source distribution: >>> zc.buildout.easy_install.develop( ... extdemo, dest, ... {'include-dirs': os.path.join(sample_buildout, 'include')}) '/sample-install/extdemo.egg-link' The name of the egg link created is returned. Now if we look in our destination directory, we see we have an extdemo egg link: >>> ls(dest) d extdemo-1.4-py2.4-unix-i686.egg - extdemo.egg-link And that the source directory contains the compiled extension: >>> ls(extdemo) - MANIFEST - MANIFEST.in - README d build - extdemo.c d extdemo.egg-info - extdemo.so - setup.py Download cache -------------- Normally, when distributions are installed, if any processing is needed, they are downloaded from the internet to a temporary directory and then installed from there. A download cache can be used to avoid the download step. This can be useful to reduce network access and to create source distributions of an entire buildout. A download cache is specified by calling the download_cache function. The function always returns the previous setting. If no argument is passed, then the setting is unchanged. If an argument is passed, the download cache is set to the given path, which must point to an existing directory. Passing None clears the cache setting. To see this work, we'll create a directory and set it as the cache directory: >>> cache = tmpdir('cache') >>> zc.buildout.easy_install.download_cache(cache) We'll recreate our destination directory: >>> remove(dest) >>> dest = tmpdir('sample-install') We'd like to see what is being fetched from the server, so we'll enable server logging: >>> get(link_server+'enable_server_logging') GET 200 /enable_server_logging '' Now, if we install demo, and extdemo: >>> ws = zc.buildout.easy_install.install( ... ['demo==0.2'], dest, ... links=[link_server], index=link_server+'index/', ... always_unzip=True) GET 200 / GET 404 /index/demo/ GET 200 /index/ GET 200 /demo-0.2-py2.4.egg GET 404 /index/demoneeded/ GET 200 /demoneeded-1.1.zip GET 404 /index/setuptools/ >>> zc.buildout.easy_install.build( ... 'extdemo', dest, ... {'include-dirs': os.path.join(sample_buildout, 'include')}, ... links=[link_server], index=link_server+'index/') GET 404 /index/extdemo/ GET 200 /extdemo-1.5.zip ['/sample-install/extdemo-1.5-py2.4-linux-i686.egg'] Not only will we get eggs in our destination directory: >>> ls(dest) d demo-0.2-py2.4.egg d demoneeded-1.1-py2.4.egg d extdemo-1.5-py2.4-linux-i686.egg But we'll get distributions in the cache directory: >>> ls(cache) - demo-0.2-py2.4.egg - demoneeded-1.1.zip - extdemo-1.5.zip The cache directory contains uninstalled distributions, such as zipped eggs or source distributions. Let's recreate our destination directory and clear the index cache: >>> remove(dest) >>> dest = tmpdir('sample-install') >>> zc.buildout.easy_install.clear_index_cache() Now when we install the distributions: >>> ws = zc.buildout.easy_install.install( ... ['demo==0.2'], dest, ... links=[link_server], index=link_server+'index/', ... always_unzip=True) GET 200 / GET 404 /index/demo/ GET 200 /index/ GET 404 /index/demoneeded/ GET 404 /index/setuptools/ >>> zc.buildout.easy_install.build( ... 'extdemo', dest, ... {'include-dirs': os.path.join(sample_buildout, 'include')}, ... links=[link_server], index=link_server+'index/') GET 404 /index/extdemo/ ['/sample-install/extdemo-1.5-py2.4-linux-i686.egg'] >>> ls(dest) d demo-0.2-py2.4.egg d demoneeded-1.1-py2.4.egg d extdemo-1.5-py2.4-linux-i686.egg Note that we didn't download the distributions from the link server. If we remove the restriction on demo, we'll download a newer version from the link server: >>> ws = zc.buildout.easy_install.install( ... ['demo'], dest, ... links=[link_server], index=link_server+'index/', ... always_unzip=True) GET 200 /demo-0.3-py2.4.egg Normally, the download cache is the prefered source of downloads, but not the only one. Installing solely from a download cache --------------------------------------- A download cache can be used as the basis of application source releases. In an application source release, we want to distribute an application that can be built without making any network accesses. In this case, we distribute a download cache and tell the easy_install module to install from the download cache only, without making network accesses. The install_from_cache function can be used to signal that packages should be installed only from the download cache. The function always returns the previous setting. Calling it with no arguments returns the current setting without changing it: >>> zc.buildout.easy_install.install_from_cache() False Calling it with a boolean value changes the setting and returns the previous setting: >>> zc.buildout.easy_install.install_from_cache(True) False Let's remove demo-0.3-py2.4.egg from the cache, clear the index cache, recreate the destination directory, and reinstall demo: >>> for f in os.listdir(cache): ... if f.startswith('demo-0.3-'): ... remove(cache, f) >>> zc.buildout.easy_install.clear_index_cache() >>> remove(dest) >>> dest = tmpdir('sample-install') >>> ws = zc.buildout.easy_install.install( ... ['demo'], dest, ... links=[link_server], index=link_server+'index/', ... always_unzip=True) >>> ls(dest) d demo-0.2-py2.4.egg d demoneeded-1.1-py2.4.egg This time, we didn't download from or even query the link server. .. Disable the download cache: >>> zc.buildout.easy_install.download_cache(None) '/cache' >>> zc.buildout.easy_install.install_from_cache(False) True