summaryrefslogtreecommitdiff
path: root/eggs/zc.buildout-1.5.2-py2.6.egg/zc/buildout/easy_install.txt
diff options
context:
space:
mode:
Diffstat (limited to 'eggs/zc.buildout-1.5.2-py2.6.egg/zc/buildout/easy_install.txt')
-rw-r--r--eggs/zc.buildout-1.5.2-py2.6.egg/zc/buildout/easy_install.txt1985
1 files changed, 1985 insertions, 0 deletions
diff --git a/eggs/zc.buildout-1.5.2-py2.6.egg/zc/buildout/easy_install.txt b/eggs/zc.buildout-1.5.2-py2.6.egg/zc/buildout/easy_install.txt
new file mode 100644
index 0000000..ec654cd
--- /dev/null
+++ b/eggs/zc.buildout-1.5.2-py2.6.egg/zc/buildout/easy_install.txt
@@ -0,0 +1,1985 @@
+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 among those already installed.
+
+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://pypi.python.org/simple/, 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 be 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 existing 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 boolean 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.
+
+use_dependency_links
+ A flag indicating whether to search for dependencies using the
+ setup dependency_links metadata or not. If true, links are searched
+ for using dependency_links in preference to other
+ locations. Defaults to true.
+
+include_site_packages
+ A flag indicating whether Python's non-standard-library packages should
+ be available for finding dependencies. Defaults to true.
+
+ Paths outside of Python's standard library--or more precisely, those that
+ are not included when Python is started with the -S argument--are loosely
+ referred to as "site-packages" here.
+
+relative_paths
+ Adjust egg paths so they are relative to the script path. This
+ allows scripts to work when scripts and eggs are moved, as long as
+ they are both moved in the same way.
+
+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="bigdemo-0.1-py2.4.egg">bigdemo-0.1-py2.4.egg</a><br>
+ <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="demo-0.4c1-py2.4.egg">demo-0.4c1-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="demoneeded-1.2c1.zip">demoneeded-1.2c1.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
+
+We got demoneeded because it was a dependency of demo.
+
+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 distributions 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 newest 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
+
+Note that we didn't get the newest versions available. There were
+release candidates for newer versions of both packages. By default,
+final releases are preferred. We can change this behavior using the
+prefer_final function:
+
+ >>> zc.buildout.easy_install.prefer_final(False)
+ True
+
+The old setting is returned.
+
+ >>> ws = zc.buildout.easy_install.install(
+ ... ['demo'], dest, links=[link_server], index=link_server+'index/')
+ >>> for dist in ws:
+ ... print dist
+ demo 0.4c1
+ demoneeded 1.2c1
+
+ >>> ls(dest)
+ - demo-0.2-py2.4.egg
+ - demo-0.3-py2.4.egg
+ - demo-0.4c1-py2.4.egg
+ - demoneeded-1.1-py2.4.egg
+ - demoneeded-1.2c1-py2.4.egg
+
+Let's put the setting back to the default.
+
+ >>> zc.buildout.easy_install.prefer_final(True)
+ False
+
+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 specific 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
+ - demo-0.4c1-py2.4.egg
+ - demoneeded-1.0-py2.4.egg
+ - demoneeded-1.1-py2.4.egg
+ - demoneeded-1.2c1-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. (Note that Distribute will unzip eggs by
+default, so if you are using Distribute, most or all eggs will already be
+unzipped without this flag.)
+
+ >>> 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=False)
+
+ >>> ls(dest)
+ - demo-0.3-py2.4.egg
+ - demoneeded-1.1-py2.4.egg
+
+We can also set a default by calling the always_unzip function:
+
+ >>> zc.buildout.easy_install.always_unzip(True)
+ False
+
+The old default is returned:
+
+ >>> rmdir(dest)
+ >>> dest = tmpdir('sample-install')
+ >>> ws = zc.buildout.easy_install.install(
+ ... ['demo'], dest, links=[link_server], index=link_server+'index/')
+
+ >>> ls(dest)
+ d demo-0.3-py2.4.egg
+ d demoneeded-1.1-py2.4.egg
+
+
+ >>> zc.buildout.easy_install.always_unzip(False)
+ True
+
+ >>> rmdir(dest)
+ >>> dest = tmpdir('sample-install')
+ >>> ws = zc.buildout.easy_install.install(
+ ... ['demo'], dest, links=[link_server], index=link_server+'index/')
+
+ >>> ls(dest)
+ - demo-0.3-py2.4.egg
+ - 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 independent of requirements
+----------------------------------------------------------
+
+Sometimes it's useful to specify version information independent 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
+dependencies 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 DEBUG
+ Picked: demo = 0.3
+ zc.buildout.easy_install DEBUG
+ Getting required 'demoneeded'
+ zc.buildout.easy_install DEBUG
+ required by demo 0.3.
+ zc.buildout.easy_install DEBUG
+ We have the best distribution that satisfies 'demoneeded'.
+ zc.buildout.easy_install DEBUG
+ Picked: demoneeded = 1.1
+
+ >>> handler.uninstall()
+ >>> logging.getLogger('zc.buildout.easy_install').propagate = True
+
+We can request that we get an error if versions are picked:
+
+ >>> zc.buildout.easy_install.allow_picked_versions(False)
+ True
+
+(The old setting is returned.)
+
+ >>> ws = zc.buildout.easy_install.install(
+ ... ['demo'], dest, links=[link_server], index=link_server+'index/',
+ ... )
+ Traceback (most recent call last):
+ ...
+ UserError: Picked: demo = 0.3
+
+ >>> zc.buildout.easy_install.allow_picked_versions(True)
+ False
+
+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']
+
+Dependencies in Site Packages
+-----------------------------
+
+Paths outside of Python's standard library--or more precisely, those that are
+not included when Python is started with the -S argument--are loosely referred
+to as "site-packages" here. These site-packages are searched by default for
+distributions. This can be disabled, so that, for instance, a system Python
+can be used with buildout, cleaned of any packages installed by a user or
+system package manager.
+
+The default behavior can be controlled and introspected using
+zc.buildout.easy_install.include_site_packages.
+
+ >>> zc.buildout.easy_install.include_site_packages()
+ True
+
+Here's an example of using a Python executable that includes our dependencies.
+
+Our "py_path" will have the "demoneeded," and "demo" packages available.
+ We'll simply be asking for "demoneeded" here, but without any external
+ index or links.
+
+ >>> from zc.buildout.tests import create_sample_sys_install
+ >>> py_path, site_packages_path = make_py()
+ >>> create_sample_sys_install(site_packages_path)
+
+ >>> example_dest = tmpdir('site-packages-example-install')
+ >>> workingset = zc.buildout.easy_install.install(
+ ... ['demoneeded'], example_dest, links=[], executable=py_path,
+ ... index=None)
+ >>> [dist.project_name for dist in workingset]
+ ['demoneeded']
+
+That worked fine. Let's try again with site packages not allowed. We'll
+change the policy by changing the default. Notice that the function for
+changing the default value returns the previous value.
+
+ >>> zc.buildout.easy_install.include_site_packages(False)
+ True
+
+ >>> zc.buildout.easy_install.include_site_packages()
+ False
+
+ >>> zc.buildout.easy_install.clear_index_cache()
+ >>> rmdir(example_dest)
+ >>> example_dest = tmpdir('site-packages-example-install')
+ >>> workingset = zc.buildout.easy_install.install(
+ ... ['demoneeded'], example_dest, links=[], executable=py_path,
+ ... index=None)
+ Traceback (most recent call last):
+ ...
+ MissingDistribution: Couldn't find a distribution for 'demoneeded'.
+ >>> zc.buildout.easy_install.clear_index_cache()
+
+Now we'll reset the default.
+
+ >>> zc.buildout.easy_install.include_site_packages(True)
+ False
+
+ >>> zc.buildout.easy_install.include_site_packages()
+ True
+
+Dependency links
+----------------
+
+Setuptools allows metadata that describes where to search for package
+dependencies. This option is called dependency_links. Buildout has its
+own notion of where to look for dependencies, but it also uses the
+setup tools dependency_links information if it's available.
+
+Let's demo this by creating an egg that specifies dependency_links.
+
+To begin, let's create a new egg repository. This repository hold a
+newer version of the 'demoneeded' egg than the sample repository does.
+
+ >>> repoloc = tmpdir('repo')
+ >>> from zc.buildout.tests import create_egg
+ >>> create_egg('demoneeded', '1.2', repoloc)
+ >>> link_server2 = start_server(repoloc)
+
+Turn on logging on this server so that we can see when eggs are pulled
+from it.
+
+ >>> get(link_server2 + 'enable_server_logging')
+ GET 200 /enable_server_logging
+ ''
+
+Now we can create an egg that specifies that its dependencies are
+found on this server.
+
+ >>> repoloc = tmpdir('repo2')
+ >>> create_egg('hasdeps', '1.0', repoloc,
+ ... install_requires = "'demoneeded'",
+ ... dependency_links = [link_server2])
+
+Let's add the egg to another repository.
+
+ >>> link_server3 = start_server(repoloc)
+
+Now let's install the egg.
+
+ >>> example_dest = tmpdir('example-install')
+ >>> workingset = zc.buildout.easy_install.install(
+ ... ['hasdeps'], example_dest,
+ ... links=[link_server3], index=link_server3+'index/')
+ GET 200 /
+ GET 200 /demoneeded-1.2-pyN.N.egg
+
+The server logs show that the dependency was retrieved from the server
+specified in the dependency_links.
+
+Now let's see what happens if we provide two different ways to retrieve
+the dependencies.
+
+ >>> rmdir(example_dest)
+ >>> example_dest = tmpdir('example-install')
+ >>> workingset = zc.buildout.easy_install.install(
+ ... ['hasdeps'], example_dest, index=link_server+'index/',
+ ... links=[link_server, link_server3])
+ GET 200 /
+ GET 200 /demoneeded-1.2-pyN.N.egg
+
+Once again the dependency is fetched from the logging server even
+though it is also available from the non-logging server. This is
+because the version on the logging server is newer and buildout
+normally chooses the newest egg available.
+
+If you wish to control where dependencies come from regardless of
+dependency_links setup metadata use the 'use_dependency_links' option
+to zc.buildout.easy_install.install().
+
+ >>> rmdir(example_dest)
+ >>> example_dest = tmpdir('example-install')
+ >>> workingset = zc.buildout.easy_install.install(
+ ... ['hasdeps'], example_dest, index=link_server+'index/',
+ ... links=[link_server, link_server3],
+ ... use_dependency_links=False)
+
+Notice that this time the dependency egg is not fetched from the
+logging server. When you specify not to use dependency_links, eggs
+will only be searched for using the links you explicitly provide.
+
+Another way to control this option is with the
+zc.buildout.easy_install.use_dependency_links() function. This
+function sets the default behavior for the zc.buildout.easy_install()
+function.
+
+ >>> zc.buildout.easy_install.use_dependency_links(False)
+ True
+
+The function returns its previous setting.
+
+ >>> rmdir(example_dest)
+ >>> example_dest = tmpdir('example-install')
+ >>> workingset = zc.buildout.easy_install.install(
+ ... ['hasdeps'], example_dest, index=link_server+'index/',
+ ... links=[link_server, link_server3])
+
+It can be overridden by passing a keyword argument to the install
+function.
+
+ >>> rmdir(example_dest)
+ >>> example_dest = tmpdir('example-install')
+ >>> workingset = zc.buildout.easy_install.install(
+ ... ['hasdeps'], example_dest, index=link_server+'index/',
+ ... links=[link_server, link_server3],
+ ... use_dependency_links=True)
+ GET 200 /demoneeded-1.2-pyN.N.egg
+
+To return the dependency_links behavior to normal call the function again.
+
+ >>> zc.buildout.easy_install.use_dependency_links(True)
+ False
+ >>> rmdir(example_dest)
+ >>> example_dest = tmpdir('example-install')
+ >>> workingset = zc.buildout.easy_install.install(
+ ... ['hasdeps'], example_dest, index=link_server+'index/',
+ ... links=[link_server, link_server3])
+ GET 200 /demoneeded-1.2-pyN.N.egg
+
+
+Script generation
+-----------------
+
+The easy_install module provides support for creating scripts from eggs.
+It provides two competing functions. One, ``scripts``, is a
+well-established approach to generating reliable scripts with a "clean"
+Python--e.g., one that does not have any packages in its site-packages.
+The other, ``sitepackage_safe_scripts``, is newer, a bit trickier, and is
+designed to work with a Python that has code in its site-packages, such
+as a system Python.
+
+Both are similar to setuptools except that they 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. (There is an exception in ``sitepackage_safe_scripts`` if you
+ want to have your Python's site packages available, as discussed
+ below, but even in that case pkg_resources is only partially
+ activated, which can be a significant time savings.)
+
+
+The ``scripts`` function
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``scripts`` function is the first way to generate scripts that we'll
+examine. It is the earlier approach that the package offered. Let's
+create a destination directory for it to place them in:
+
+ >>> bin = tmpdir('bin')
+
+Now, we'll use the scripts function 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 entry 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
+ <BLANKLINE>
+ import sys
+ <BLANKLINE>
+ sys.path[0:0] = [
+ '/sample-install/demo-0.3-pyN.N.egg',
+ '/sample-install/demoneeded-1.1-pyN.N.egg',
+ ]
+ <BLANKLINE>
+ _interactive = True
+ if len(sys.argv) > 1:
+ _options, _args = __import__("getopt").getopt(sys.argv[1:], 'ic:m:')
+ _interactive = False
+ for (_opt, _val) in _options:
+ if _opt == '-i':
+ _interactive = True
+ elif _opt == '-c':
+ exec _val
+ elif _opt == '-m':
+ sys.argv[1:] = _args
+ _args = []
+ __import__("runpy").run_module(
+ _val, {}, "__main__", alter_sys=True)
+ <BLANKLINE>
+ if _args:
+ sys.argv[:] = _args
+ __file__ = _args[0]
+ del _options, _args
+ execfile(__file__)
+ <BLANKLINE>
+ if _interactive:
+ del _interactive
+ __import__("code").interact(banner="", local=globals())
+
+If invoked with a script name and arguments, it will run that script, instead.
+
+ >>> write('ascript', '''
+ ... "demo doc"
+ ... print sys.argv
+ ... print (__name__, __file__, __doc__)
+ ... ''')
+ >>> print system(join(bin, 'py')+' ascript a b c'),
+ ['ascript', 'a', 'b', 'c']
+ ('__main__', 'ascript', 'demo doc')
+
+For Python 2.5 and higher, you can also use the -m option to run a
+module:
+
+ >>> print system(join(bin, 'py')+' -m pdb'),
+ usage: pdb.py scriptfile [arg] ...
+
+ >>> print system(join(bin, 'py')+' -m pdb what'),
+ Error: what does not exist
+
+An additional argument 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
+
+The ``scripts`` function: Including extra paths in scripts
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We can pass a keyword argument, extra paths, to cause additional paths
+to be included in the a generated script:
+
+ >>> foo = tmpdir('foo')
+ >>> scripts = zc.buildout.easy_install.scripts(
+ ... ['demo'], ws, sys.executable, bin, dict(demo='run'),
+ ... extra_paths=[foo])
+
+ >>> 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',
+ ]
+ <BLANKLINE>
+ import eggrecipedemo
+ <BLANKLINE>
+ if __name__ == '__main__':
+ eggrecipedemo.main()
+
+The ``scripts`` function: 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)
+
+The ``scripts`` function: 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)
+
+The ``scripts`` function: Relative paths
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes, you want to be able to move a buildout directory around and
+have scripts still work without having to rebuild them. We can
+control this using the relative_paths option to install. You need
+to pass a common base directory of the scripts and eggs:
+
+ >>> bo = tmpdir('bo')
+ >>> ba = tmpdir('ba')
+ >>> mkdir(bo, 'eggs')
+ >>> mkdir(bo, 'bin')
+ >>> mkdir(bo, 'other')
+
+ >>> ws = zc.buildout.easy_install.install(
+ ... ['demo'], join(bo, 'eggs'), links=[link_server],
+ ... index=link_server+'index/')
+
+ >>> scripts = zc.buildout.easy_install.scripts(
+ ... ['demo'], ws, sys.executable, join(bo, 'bin'), dict(demo='run'),
+ ... extra_paths=[ba, join(bo, 'bar')],
+ ... interpreter='py',
+ ... relative_paths=bo)
+
+ >>> cat(bo, 'bin', 'run') # doctest: +NORMALIZE_WHITESPACE
+ #!/usr/local/bin/python2.4
+ <BLANKLINE>
+ import os
+ <BLANKLINE>
+ join = os.path.join
+ base = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
+ base = os.path.dirname(base)
+ <BLANKLINE>
+ import sys
+ sys.path[0:0] = [
+ join(base, 'eggs/demo-0.3-pyN.N.egg'),
+ join(base, 'eggs/demoneeded-1.1-pyN.N.egg'),
+ '/ba',
+ join(base, 'bar'),
+ ]
+ <BLANKLINE>
+ import eggrecipedemo
+ <BLANKLINE>
+ if __name__ == '__main__':
+ eggrecipedemo.main()
+
+Note that the extra path we specified that was outside the directory
+passed as relative_paths wasn't converted to a relative path.
+
+Of course, running the script works:
+
+ >>> print system(join(bo, 'bin', 'run')),
+ 3 1
+
+We specified an interpreter and its paths are adjusted too:
+
+ >>> cat(bo, 'bin', 'py') # doctest: +NORMALIZE_WHITESPACE
+ #!/usr/local/bin/python2.4
+ <BLANKLINE>
+ import os
+ <BLANKLINE>
+ join = os.path.join
+ base = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
+ base = os.path.dirname(base)
+ <BLANKLINE>
+ import sys
+ <BLANKLINE>
+ sys.path[0:0] = [
+ join(base, 'eggs/demo-0.3-pyN.N.egg'),
+ join(base, 'eggs/demoneeded-1.1-pyN.N.egg'),
+ '/ba',
+ join(base, 'bar'),
+ ]
+ <BLANKLINE>
+ _interactive = True
+ if len(sys.argv) > 1:
+ _options, _args = __import__("getopt").getopt(sys.argv[1:], 'ic:m:')
+ _interactive = False
+ for (_opt, _val) in _options:
+ if _opt == '-i':
+ _interactive = True
+ elif _opt == '-c':
+ exec _val
+ elif _opt == '-m':
+ sys.argv[1:] = _args
+ _args = []
+ __import__("runpy").run_module(
+ _val, {}, "__main__", alter_sys=True)
+ <BLANKLINE>
+ if _args:
+ sys.argv[:] = _args
+ __file__ = _args[0]
+ del _options, _args
+ execfile(__file__)
+ <BLANKLINE>
+ if _interactive:
+ del _interactive
+ __import__("code").interact(banner="", local=globals())
+
+The ``sitepackage_safe_scripts`` function
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The newer function for creating scripts is ``sitepackage_safe_scripts``.
+It has the same basic functionality as the ``scripts`` function: it can
+create scripts to run arbitrary entry points, and to run a Python
+interpreter. The following are the differences from a user's
+perspective.
+
+- It can be used safely with a Python that has packages installed itself,
+ such as a system-installed Python.
+
+- In contrast to the interpreter generated by the ``scripts`` method, which
+ supports only a small subset of the usual Python executable's options,
+ the interpreter generated by ``sitepackage_safe_scripts`` supports all
+ of them. This makes it possible to use as full Python replacement for
+ scripts that need the distributions specified in your buildout.
+
+- Both the interpreter and the entry point scripts allow you to include the
+ site packages, and/or the sitecustomize, of the Python executable, if
+ desired.
+
+It works by creating site.py and sitecustomize.py files that set up the
+desired paths and initialization. These must be placed within an otherwise
+empty directory. Typically this is in a recipe's parts directory.
+
+Here's the simplest example, building an interpreter script.
+
+ >>> interpreter_dir = tmpdir('interpreter')
+ >>> interpreter_parts_dir = os.path.join(
+ ... interpreter_dir, 'parts', 'interpreter')
+ >>> interpreter_bin_dir = os.path.join(interpreter_dir, 'bin')
+ >>> mkdir(interpreter_bin_dir)
+ >>> mkdir(interpreter_dir, 'eggs')
+ >>> mkdir(interpreter_dir, 'parts')
+ >>> mkdir(interpreter_parts_dir)
+
+ >>> ws = zc.buildout.easy_install.install(
+ ... ['demo'], join(interpreter_dir, 'eggs'), links=[link_server],
+ ... index=link_server+'index/')
+ >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
+ ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
+ ... interpreter='py')
+
+Depending on whether the machine being used is running Windows or not, this
+produces either three or four files. In both cases, we have site.py and
+sitecustomize.py generated in the parts/interpreter directory. For Windows,
+we have py.exe and py-script.py; for other operating systems, we have py.
+
+ >>> sitecustomize_path = os.path.join(
+ ... interpreter_parts_dir, 'sitecustomize.py')
+ >>> site_path = os.path.join(interpreter_parts_dir, 'site.py')
+ >>> interpreter_path = os.path.join(interpreter_bin_dir, 'py')
+ >>> if sys.platform == 'win32':
+ ... py_path = os.path.join(interpreter_bin_dir, 'py-script.py')
+ ... expected = [sitecustomize_path,
+ ... site_path,
+ ... os.path.join(interpreter_bin_dir, 'py.exe'),
+ ... py_path]
+ ... else:
+ ... py_path = interpreter_path
+ ... expected = [sitecustomize_path, site_path, py_path]
+ ...
+ >>> assert generated == expected, repr((generated, expected))
+
+We didn't ask for any initialization, and we didn't ask to use the underlying
+sitecustomization, so sitecustomize.py is empty.
+
+ >>> cat(sitecustomize_path)
+
+The interpreter script is simple. It puts the directory with the
+site.py and sitecustomize.py on the PYTHONPATH and (re)starts Python.
+
+ >>> cat(py_path)
+ #!/usr/bin/python -S
+ import os
+ import sys
+ <BLANKLINE>
+ argv = [sys.executable] + sys.argv[1:]
+ environ = os.environ.copy()
+ path = '/interpreter/parts/interpreter'
+ if environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, environ['PYTHONPATH']])
+ environ['PYTHONPATH'] = path
+ os.execve(sys.executable, argv, environ)
+
+The site.py file is a modified version of the underlying Python's site.py.
+The most important modification is that it has a different version of the
+addsitepackages function. It sets up the Python path, similarly to the
+behavior of the function it replaces. The following shows the part that
+buildout inserts, in the simplest case.
+
+ >>> sys.stdout.write('#\n'); cat(site_path)
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ #...
+ def addsitepackages(known_paths):
+ """Add site packages, as determined by zc.buildout.
+ <BLANKLINE>
+ See original_addsitepackages, below, for the original version."""
+ buildout_paths = [
+ '/interpreter/eggs/demo-0.3-pyN.N.egg',
+ '/interpreter/eggs/demoneeded-1.1-pyN.N.egg'
+ ]
+ for path in buildout_paths:
+ sitedir, sitedircase = makepath(path)
+ if not sitedircase in known_paths and os.path.exists(sitedir):
+ sys.path.append(sitedir)
+ known_paths.add(sitedircase)
+ return known_paths
+ <BLANKLINE>
+ def original_addsitepackages(known_paths):...
+
+Here are some examples of the interpreter in use.
+
+ >>> print call_py(interpreter_path, "print 16+26")
+ 42
+ <BLANKLINE>
+ >>> res = call_py(interpreter_path, "import sys; print sys.path")
+ >>> print res # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ ['',
+ '/interpreter/parts/interpreter',
+ ...,
+ '/interpreter/eggs/demo-0.3-pyN.N.egg',
+ '/interpreter/eggs/demoneeded-1.1-pyN.N.egg']
+ <BLANKLINE>
+ >>> clean_paths = eval(res.strip()) # This is used later for comparison.
+
+If you provide initialization, it goes in sitecustomize.py.
+
+ >>> def reset_interpreter():
+ ... # This is necessary because, in our tests, the timestamps of the
+ ... # .pyc files are not outdated when we want them to be.
+ ... rmdir(interpreter_bin_dir)
+ ... mkdir(interpreter_bin_dir)
+ ... rmdir(interpreter_parts_dir)
+ ... mkdir(interpreter_parts_dir)
+ ...
+ >>> reset_interpreter()
+
+ >>> initialization_string = """\
+ ... import os
+ ... os.environ['FOO'] = 'bar baz bing shazam'"""
+ >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
+ ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
+ ... interpreter='py', initialization=initialization_string)
+ >>> cat(sitecustomize_path)
+ import os
+ os.environ['FOO'] = 'bar baz bing shazam'
+ >>> print call_py(interpreter_path, "import os; print os.environ['FOO']")
+ bar baz bing shazam
+ <BLANKLINE>
+
+If you use relative paths, this affects the interpreter and site.py. (This is
+again the UNIX version; the Windows version uses subprocess instead of
+os.execve.)
+
+ >>> reset_interpreter()
+ >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
+ ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
+ ... interpreter='py', relative_paths=interpreter_dir)
+ >>> cat(py_path)
+ #!/usr/bin/python -S
+ import os
+ import sys
+ <BLANKLINE>
+ join = os.path.join
+ base = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
+ base = os.path.dirname(base)
+ <BLANKLINE>
+ argv = [sys.executable] + sys.argv[1:]
+ environ = os.environ.copy()
+ path = join(base, 'parts/interpreter')
+ if environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, environ['PYTHONPATH']])
+ environ['PYTHONPATH'] = path
+ os.execve(sys.executable, argv, environ)
+
+For site.py, we again show only the pertinent parts. Notice that the egg
+paths join a base to a path, as with the use of this argument in the
+``scripts`` function.
+
+ >>> sys.stdout.write('#\n'); cat(site_path) # doctest: +ELLIPSIS
+ #...
+ def addsitepackages(known_paths):
+ """Add site packages, as determined by zc.buildout.
+ <BLANKLINE>
+ See original_addsitepackages, below, for the original version."""
+ join = os.path.join
+ base = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
+ base = os.path.dirname(base)
+ base = os.path.dirname(base)
+ buildout_paths = [
+ join(base, 'eggs/demo-0.3-pyN.N.egg'),
+ join(base, 'eggs/demoneeded-1.1-pyN.N.egg')
+ ]...
+
+The paths resolve in practice as you would expect.
+
+ >>> print call_py(interpreter_path,
+ ... "import sys, pprint; pprint.pprint(sys.path)")
+ ... # doctest: +ELLIPSIS
+ ['',
+ '/interpreter/parts/interpreter',
+ ...,
+ '/interpreter/eggs/demo-0.3-pyN.N.egg',
+ '/interpreter/eggs/demoneeded-1.1-pyN.N.egg']
+ <BLANKLINE>
+
+The ``extra_paths`` argument affects the path in site.py. Notice that
+/interpreter/other is added after the eggs.
+
+ >>> reset_interpreter()
+ >>> mkdir(interpreter_dir, 'other')
+ >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
+ ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
+ ... interpreter='py', extra_paths=[join(interpreter_dir, 'other')])
+ >>> sys.stdout.write('#\n'); cat(site_path) # doctest: +ELLIPSIS
+ #...
+ def addsitepackages(known_paths):
+ """Add site packages, as determined by zc.buildout.
+ <BLANKLINE>
+ See original_addsitepackages, below, for the original version."""
+ buildout_paths = [
+ '/interpreter/eggs/demo-0.3-pyN.N.egg',
+ '/interpreter/eggs/demoneeded-1.1-pyN.N.egg',
+ '/interpreter/other'
+ ]...
+
+ >>> print call_py(interpreter_path,
+ ... "import sys, pprint; pprint.pprint(sys.path)")
+ ... # doctest: +ELLIPSIS
+ ['',
+ '/interpreter/parts/interpreter',
+ ...,
+ '/interpreter/eggs/demo-0.3-pyN.N.egg',
+ '/interpreter/eggs/demoneeded-1.1-pyN.N.egg',
+ '/interpreter/other']
+ <BLANKLINE>
+
+The ``sitepackage_safe_scripts`` function: using site-packages
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``sitepackage_safe_scripts`` function supports including site
+packages. This has some advantages and some serious dangers.
+
+A typical reason to include site-packages is that it is easier to
+install one or more dependencies in your Python than it is with
+buildout. Some packages, such as lxml or Python PostgreSQL integration,
+have dependencies that can be much easier to build and/or install using
+other mechanisms, such as your operating system's package manager. By
+installing some core packages into your Python's site-packages, this can
+significantly simplify some application installations.
+
+However, doing this has a significant danger. One of the primary goals
+of buildout is to provide repeatability. Some packages (one of the
+better known Python openid packages, for instance) change their behavior
+depending on what packages are available. If Python curl bindings are
+available, these may be preferred by the library. If a certain XML
+package is installed, it may be preferred by the library. These hidden
+choices may cause small or large behavior differences. The fact that
+they can be rarely encountered can actually make it worse: you forget
+that this might be a problem, and debugging the differences can be
+difficult. If you allow site-packages to be included in your buildout,
+and the Python you use is not managed precisely by your application (for
+instance, it is a system Python), you open yourself up to these
+possibilities. Don't be unaware of the dangers.
+
+That explained, let's see how it works. If you don't use namespace packages,
+this is very straightforward.
+
+ >>> reset_interpreter()
+ >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
+ ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
+ ... interpreter='py', include_site_packages=True)
+ >>> sys.stdout.write('#\n'); cat(site_path)
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ #...
+ def addsitepackages(known_paths):
+ """Add site packages, as determined by zc.buildout.
+ <BLANKLINE>
+ See original_addsitepackages, below, for the original version."""
+ setuptools_path = None
+ buildout_paths = [
+ '/interpreter/eggs/demo-0.3-pyN.N.egg',
+ '/interpreter/eggs/demoneeded-1.1-pyN.N.egg'
+ ]
+ for path in buildout_paths:
+ sitedir, sitedircase = makepath(path)
+ if not sitedircase in known_paths and os.path.exists(sitedir):
+ sys.path.append(sitedir)
+ known_paths.add(sitedircase)
+ sys.__egginsert = len(buildout_paths) # Support distribute.
+ original_paths = [
+ ...
+ ]
+ for path in original_paths:
+ if path == setuptools_path or path not in known_paths:
+ addsitedir(path, known_paths)
+ return known_paths
+ <BLANKLINE>
+ def original_addsitepackages(known_paths):...
+
+It simply adds the original paths using addsitedir after the code to add the
+buildout paths.
+
+Here's an example of the new script in use. Other documents and tests in
+this package give the feature a more thorough workout, but this should
+give you an idea of the feature.
+
+ >>> res = call_py(interpreter_path, "import sys; print sys.path")
+ >>> print res # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ ['',
+ '/interpreter/parts/interpreter',
+ ...,
+ '/interpreter/eggs/demo-0.3-py2.4.egg',
+ '/interpreter/eggs/demoneeded-1.1-py2.4.egg',
+ ...]
+ <BLANKLINE>
+
+The clean_paths gathered earlier is a subset of this full list of paths.
+
+ >>> full_paths = eval(res.strip())
+ >>> len(clean_paths) < len(full_paths)
+ True
+ >>> set(os.path.normpath(p) for p in clean_paths).issubset(
+ ... os.path.normpath(p) for p in full_paths)
+ True
+
+Unfortunately, because of how setuptools namespace packages are implemented
+differently for operating system packages (debs or rpms) as opposed to
+standard setuptools installation, there's a slightly trickier dance if you
+use them. To show this we'll needs some extra eggs that use namespaces.
+We'll use the ``tellmy.fortune`` package, which we'll need to make an initial
+call to another text fixture to create.
+
+ >>> from zc.buildout.tests import create_sample_namespace_eggs
+ >>> namespace_eggs = tmpdir('namespace_eggs')
+ >>> create_sample_namespace_eggs(namespace_eggs)
+
+ >>> reset_interpreter()
+ >>> ws = zc.buildout.easy_install.install(
+ ... ['demo', 'tellmy.fortune'], join(interpreter_dir, 'eggs'),
+ ... links=[link_server, namespace_eggs], index=link_server+'index/')
+ >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
+ ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
+ ... interpreter='py', include_site_packages=True)
+ >>> sys.stdout.write('#\n'); cat(site_path)
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ #...
+ def addsitepackages(known_paths):
+ """Add site packages, as determined by zc.buildout.
+ <BLANKLINE>
+ See original_addsitepackages, below, for the original version."""
+ setuptools_path = '...setuptools...'
+ sys.path.append(setuptools_path)
+ known_paths.add(os.path.normcase(setuptools_path))
+ import pkg_resources
+ buildout_paths = [
+ '/interpreter/eggs/demo-0.3-pyN.N.egg',
+ '/interpreter/eggs/tellmy.fortune-1.0-pyN.N.egg',
+ '...setuptools...',
+ '/interpreter/eggs/demoneeded-1.1-pyN.N.egg'
+ ]
+ for path in buildout_paths:
+ sitedir, sitedircase = makepath(path)
+ if not sitedircase in known_paths and os.path.exists(sitedir):
+ sys.path.append(sitedir)
+ known_paths.add(sitedircase)
+ pkg_resources.working_set.add_entry(sitedir)
+ sys.__egginsert = len(buildout_paths) # Support distribute.
+ original_paths = [
+ ...
+ ]
+ for path in original_paths:
+ if path == setuptools_path or path not in known_paths:
+ addsitedir(path, known_paths)
+ return known_paths
+ <BLANKLINE>
+ def original_addsitepackages(known_paths):...
+
+ >>> print call_py(interpreter_path, "import sys; print sys.path")
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ ['',
+ '/interpreter/parts/interpreter',
+ ...,
+ '...setuptools...',
+ '/interpreter/eggs/demo-0.3-pyN.N.egg',
+ '/interpreter/eggs/tellmy.fortune-1.0-pyN.N.egg',
+ '/interpreter/eggs/demoneeded-1.1-pyN.N.egg',
+ ...]
+
+As you can see, the script now first imports pkg_resources. Then we
+need to process egg files specially to look for namespace packages there
+*before* we process process lines in .pth files that use the "import"
+feature--lines that might be part of the setuptools namespace package
+implementation for system packages, as mentioned above, and that must
+come after processing egg namespaces.
+
+The most complex that this function gets is if you use namespace packages,
+include site-packages, and use relative paths. For completeness, we'll look
+at that result.
+
+ >>> reset_interpreter()
+ >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
+ ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
+ ... interpreter='py', include_site_packages=True,
+ ... relative_paths=interpreter_dir)
+ >>> sys.stdout.write('#\n'); cat(site_path)
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ #...
+ def addsitepackages(known_paths):
+ """Add site packages, as determined by zc.buildout.
+ <BLANKLINE>
+ See original_addsitepackages, below, for the original version."""
+ join = os.path.join
+ base = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
+ base = os.path.dirname(base)
+ base = os.path.dirname(base)
+ setuptools_path = '...setuptools...'
+ sys.path.append(setuptools_path)
+ known_paths.add(os.path.normcase(setuptools_path))
+ import pkg_resources
+ buildout_paths = [
+ join(base, 'eggs/demo-0.3-pyN.N.egg'),
+ join(base, 'eggs/tellmy.fortune-1.0-pyN.N.egg'),
+ '...setuptools...',
+ join(base, 'eggs/demoneeded-1.1-pyN.N.egg')
+ ]
+ for path in buildout_paths:
+ sitedir, sitedircase = makepath(path)
+ if not sitedircase in known_paths and os.path.exists(sitedir):
+ sys.path.append(sitedir)
+ known_paths.add(sitedircase)
+ pkg_resources.working_set.add_entry(sitedir)
+ sys.__egginsert = len(buildout_paths) # Support distribute.
+ original_paths = [
+ ...
+ ]
+ for path in original_paths:
+ if path == setuptools_path or path not in known_paths:
+ addsitedir(path, known_paths)
+ return known_paths
+ <BLANKLINE>
+ def original_addsitepackages(known_paths):...
+
+ >>> print call_py(interpreter_path, "import sys; print sys.path")
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ ['',
+ '/interpreter/parts/interpreter',
+ ...,
+ '...setuptools...',
+ '/interpreter/eggs/demo-0.3-pyN.N.egg',
+ '/interpreter/eggs/tellmy.fortune-1.0-pyN.N.egg',
+ '/interpreter/eggs/demoneeded-1.1-pyN.N.egg',
+ ...]
+
+The ``exec_sitecustomize`` argument does the same thing for the
+sitecustomize module--it allows you to include the code from the
+sitecustomize module in the underlying Python if you set the argument to
+True. The z3c.recipe.scripts package sets up the full environment necessary
+to demonstrate this piece.
+
+The ``sitepackage_safe_scripts`` function: writing scripts for entry points
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+All of the examples so far for this function have been creating
+interpreters. The function can also write scripts for entry
+points. They are almost identical to the scripts that we saw for the
+``scripts`` function except that they ``import site`` after setting the
+sys.path to include our custom site.py and sitecustomize.py files. These
+files then initialize the Python environment as we have already seen. Let's
+see a simple example.
+
+ >>> reset_interpreter()
+ >>> ws = zc.buildout.easy_install.install(
+ ... ['demo'], join(interpreter_dir, 'eggs'), links=[link_server],
+ ... index=link_server+'index/')
+ >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
+ ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
+ ... reqs=['demo'])
+
+As before, 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. This is in addition
+to the site.py and sitecustomize.py files that are generated as with our
+interpreter examples above.
+
+ >>> if sys.platform == 'win32':
+ ... demo_path = os.path.join(interpreter_bin_dir, 'demo-script.py')
+ ... expected = [sitecustomize_path,
+ ... site_path,
+ ... os.path.join(interpreter_bin_dir, 'demo.exe'),
+ ... demo_path]
+ ... else:
+ ... demo_path = os.path.join(interpreter_bin_dir, 'demo')
+ ... expected = [sitecustomize_path, site_path, demo_path]
+ ...
+ >>> assert generated == expected, repr((generated, expected))
+
+The demo script runs the entry point defined in the demo egg:
+
+ >>> cat(demo_path) # doctest: +NORMALIZE_WHITESPACE
+ #!/usr/local/bin/python2.4 -S
+ <BLANKLINE>
+ import sys
+ sys.path[0:0] = [
+ '/interpreter/parts/interpreter',
+ ]
+ <BLANKLINE>
+ <BLANKLINE>
+ import os
+ path = sys.path[0]
+ if os.environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, os.environ['PYTHONPATH']])
+ os.environ['BUILDOUT_ORIGINAL_PYTHONPATH'] = os.environ.get('PYTHONPATH', '')
+ os.environ['PYTHONPATH'] = path
+ import site # imports custom buildout-generated site.py
+ <BLANKLINE>
+ import eggrecipedemo
+ <BLANKLINE>
+ if __name__ == '__main__':
+ eggrecipedemo.main()
+
+ >>> demo_call = join(interpreter_bin_dir, 'demo')
+ >>> if sys.platform == 'win32':
+ ... demo_call = '"%s"' % demo_call
+ >>> print system(demo_call)
+ 3 1
+ <BLANKLINE>
+
+There are a few differences from the ``scripts`` function. First, the
+``reqs`` argument (an iterable of string requirements or entry point
+tuples) is a keyword argument here. We see that in the example above.
+Second, the ``arguments`` argument is now named ``script_arguments`` to
+try and clarify that it does not affect interpreters. While the
+``initialization`` argument continues to affect both the interpreters
+and the entry point scripts, if you have initialization that is only
+pertinent to the entry point scripts, you can use the
+``script_initialization`` argument.
+
+Let's see ``script_arguments`` and ``script_initialization`` in action.
+
+ >>> reset_interpreter()
+ >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
+ ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
+ ... reqs=['demo'], script_arguments='1, 2',
+ ... script_initialization='import os\nos.chdir("foo")')
+
+ >>> cat(demo_path) # doctest: +NORMALIZE_WHITESPACE
+ #!/usr/local/bin/python2.4 -S
+ import sys
+ sys.path[0:0] = [
+ '/interpreter/parts/interpreter',
+ ]
+ <BLANKLINE>
+ import os
+ path = sys.path[0]
+ if os.environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, os.environ['PYTHONPATH']])
+ os.environ['BUILDOUT_ORIGINAL_PYTHONPATH'] = os.environ.get('PYTHONPATH', '')
+ os.environ['PYTHONPATH'] = path
+ import site # imports custom buildout-generated site.py
+ 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://pypi.python.org/simple/, 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 be 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 boolean 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="bigdemo-0.1-py2.4.egg">bigdemo-0.1-py2.4.egg</a><br>
+ <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="demo-0.4c1-py2.4.egg">demo-0.4c1-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="demoneeded-1.2c1.zip">demoneeded-1.2c1.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 destination 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 be 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
+
+ >>> 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/
+
+ >>> 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 preferred 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