Merge lp:~gary/zc.buildout/python-support-5-initial-egg-control into lp:zc.buildout

Proposed by Gary Poster
Status: Needs review
Proposed branch: lp:~gary/zc.buildout/python-support-5-initial-egg-control
Merge into: lp:zc.buildout
Prerequisite: lp:~gary/zc.buildout/python-support-4
Diff against target: 1188 lines (+651/-156)
8 files modified
.bzrignore (+9/-0)
src/zc/buildout/easy_install.py (+223/-104)
src/zc/buildout/easy_install.txt (+73/-3)
src/zc/buildout/testing.py (+33/-6)
src/zc/buildout/tests.py (+301/-31)
z3c.recipe.scripts_/src/z3c/recipe/scripts/README.txt (+5/-5)
z3c.recipe.scripts_/src/z3c/recipe/scripts/scripts.py (+6/-6)
z3c.recipe.scripts_/src/z3c/recipe/scripts/tests.py (+1/-1)
To merge this branch: bzr merge lp:~gary/zc.buildout/python-support-5-initial-egg-control
Reviewer Review Type Date Requested Status
Francis J. Lacoste (community) Approve
Review via email: mp+20010@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Gary Poster (gary) wrote :

This branch builds the infrastructure in easy_install that is needed for z3c.recipe.scripts to control what packages from site-packages can be used to fulfill setup.py dependencies. Hooking it up comes in the subsequent branch, ~gary/zc.buildout/python-support-6-egg-control .

This branch merged the remaining work from my previous zc.buildout effort. Much of this branch has therefore been reviewed before.

In the previous branch, I had a flag called "include-site-packages" (or "include_site_packages" depending on whether it is a config file or Python) for behavior related to what I had been calling "add-site-packages" (or "add_site_packages") in the more recent effort. I settled on "include-site-packages"/"include_site_packages" because it seemed to me to better describe the behavior of the flag, particularly in the case of the zc.buildout.easy_install.include_site_packages function.

My addition and use of _get_version_info is new to this branch. It seems OK to me, but I questioned it, and would welcome other ideas. You'll notice that previously buildout indiscriminately added the buildout and setuptools paths. I felt that being more careful was warranted, but maybe I'm wrong.

I noticed a couple of intermittent test failures during the development of this branch. I got them to go away with the use of get_installer_values and set_installer_values for careful teardowns of various test changes. This work is also new.

That's it. Thank you.

Gary

Revision history for this message
Gary Poster (gary) wrote :

Note also that I moved _get_system_paths to the top of easy_install.py because it was now used by both the Installer and sitepackage_safe_scripts. It is not new code.

Revision history for this message
Francis J. Lacoste (flacoste) wrote :

Hi Gary,

My only comment is about some API incompatible changes you made. Not sure it's a problem or not. Otherwise, all fine.

> === modified file 'src/zc/buildout/easy_install.py'

> def use_dependency_links(setting=None):
> old = Installer._use_dependency_links
> if setting is not None:
> @@ -858,9 +1014,13 @@
> links=(), index=None,
> executable=sys.executable, always_unzip=None,
> path=None, working_set=None, newest=True, versions=None,
> - use_dependency_links=None, allow_hosts=('*',)):
> + use_dependency_links=None, include_site_packages=None,
> + allowed_eggs_from_site_packages=None, allow_hosts=('*',)):
> installer = Installer(dest, links, index, executable, always_unzip, path,
> newest, versions, use_dependency_links,
> + include_site_packages=include_site_packages,
> + allowed_eggs_from_site_packages=
> + allowed_eggs_from_site_packages,
> allow_hosts=allow_hosts)
> return installer.install(specs, working_set)
>
> @@ -868,9 +1028,14 @@
> def build(spec, dest, build_ext,
> links=(), index=None,
> executable=sys.executable,
> - path=None, newest=True, versions=None, allow_hosts=('*',)):
> + path=None, newest=True, versions=None, include_site_packages=None,
> + allowed_eggs_from_site_packages=None, allow_hosts=('*',)):
> installer = Installer(dest, links, index, executable, True, path, newest,
> - versions, allow_hosts=allow_hosts)
> + versions,
> + include_site_packages=include_site_packages,
> + allowed_eggs_from_site_packages=
> + allowed_eggs_from_site_packages,
> + allow_hosts=allow_hosts)
> return installer.build(spec, build_ext)
>

Should we care about API compatibility in these two functions? You added
parameters before allow_hosts. Theorically, this breaks API compatibility for
call sites passing things by parameters. Arguably a bad idea with such a
signature, but it's your call :-)

review: Approve
555. By Gary Poster

be a better backwards-compatibilty citizen

Revision history for this message
Gary Poster (gary) wrote :

Yeah, what I did was on purpose and after consideration, but maybe wrong all the same. :-) I changed it.

Thanks!

Unmerged revisions

555. By Gary Poster

be a better backwards-compatibilty citizen

554. By Gary Poster

merge from gary-4

553. By Gary Poster

merge from gary-4

552. By Gary Poster

settle on "include-site-packages" and migrate all variations of "add-site-packages" to that spelling.

551. By Gary Poster

merge from gary-4

550. By Gary Poster

support limiting packages from site-packages

549. By Gary Poster

propagate merge from gary-3 <- gary-2 <- gary-1 <- trunk

548. By gary

fix some tests on other Python versions

547. By gary

revert attempt to skip some of the pkg_resources dance: it caused me trouble.

546. By gary

simplify resulting code a bit more and try again to remove warnings

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file '.bzrignore'
--- .bzrignore 1970-01-01 00:00:00 +0000
+++ .bzrignore 2010-02-24 23:22:13 +0000
@@ -0,0 +1,9 @@
1.installed.cfg
2bin
3build
4develop-eggs
5eggs
6parts
7src/zc.buildout.egg-info
8z3c.recipe.scripts_/src/z3c.recipe.scripts.egg-info
9zc.recipe.egg_/src/zc.recipe.egg.egg-info
010
=== modified file 'src/zc/buildout/easy_install.py'
--- src/zc/buildout/easy_install.py 2010-02-24 23:22:13 +0000
+++ src/zc/buildout/easy_install.py 2010-02-24 23:22:13 +0000
@@ -19,6 +19,7 @@
19"""19"""
2020
21import distutils.errors21import distutils.errors
22import fnmatch
22import glob23import glob
23import logging24import logging
24import os25import os
@@ -68,6 +69,64 @@
68if os.path.normpath(setuptools_loc) != os.path.normpath(buildout_loc):69if os.path.normpath(setuptools_loc) != os.path.normpath(buildout_loc):
69 buildout_and_setuptools_path.append(buildout_loc)70 buildout_and_setuptools_path.append(buildout_loc)
7071
72def _get_system_paths(executable):
73 """Return lists of standard lib and site paths for executable.
74 """
75 # We want to get a list of the site packages, which is not easy.
76 # The canonical way to do this is to use
77 # distutils.sysconfig.get_python_lib(), but that only returns a
78 # single path, which does not reflect reality for many system
79 # Pythons, which have multiple additions. Instead, we start Python
80 # with -S, which does not import site.py and set up the extra paths
81 # like site-packages or (Ubuntu/Debian) dist-packages and
82 # python-support. We then compare that sys.path with the normal one
83 # (minus user packages if this is Python 2.6, because we don't
84 # support those (yet?). The set of the normal one minus the set of
85 # the ones in ``python -S`` is the set of packages that are
86 # effectively site-packages.
87 #
88 # The given executable might not be the current executable, so it is
89 # appropriate to do another subprocess to figure out what the
90 # additional site-package paths are. Moreover, even if this
91 # executable *is* the current executable, this code might be run in
92 # the context of code that has manipulated the sys.path--for
93 # instance, to add local zc.buildout or setuptools eggs.
94 def get_sys_path(*args, **kwargs):
95 cmd = [executable]
96 cmd.extend(args)
97 cmd.extend([
98 "-c", "import sys, os;"
99 "print repr([os.path.normpath(p) for p in sys.path if p])"])
100 # Windows needs some (as yet to be determined) part of the real env.
101 env = os.environ.copy()
102 env.update(kwargs)
103 _proc = subprocess.Popen(
104 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
105 stdout, stderr = _proc.communicate();
106 if _proc.returncode:
107 raise RuntimeError(
108 'error trying to get system packages:\n%s' % (stderr,))
109 res = eval(stdout.strip())
110 try:
111 res.remove('.')
112 except ValueError:
113 pass
114 return res
115 stdlib = get_sys_path('-S') # stdlib only
116 no_user_paths = get_sys_path(PYTHONNOUSERSITE='x')
117 site_paths = [p for p in no_user_paths if p not in stdlib]
118 return (stdlib, site_paths)
119
120def _get_version_info(executable):
121 cmd = [executable, '-Sc', 'import sys; print repr(sys.version_info)']
122 _proc = subprocess.Popen(
123 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
124 stdout, stderr = _proc.communicate();
125 if _proc.returncode:
126 raise RuntimeError(
127 'error trying to get system packages:\n%s' % (stderr,))
128 return eval(stdout.strip())
129
71130
72class IncompatibleVersionError(zc.buildout.UserError):131class IncompatibleVersionError(zc.buildout.UserError):
73 """A specified version is incompatible with a given requirement.132 """A specified version is incompatible with a given requirement.
@@ -110,7 +169,12 @@
110169
111170
112_indexes = {}171_indexes = {}
113def _get_index(executable, index_url, find_links, allow_hosts=('*',)):172def _get_index(executable, index_url, find_links, allow_hosts=('*',),
173 path=None):
174 # If path is None, the index will use sys.path. If you provide an empty
175 # path ([]), it will complain uselessly about missing index pages for
176 # packages found in the paths that you expect to use. Therefore, this path
177 # is always the same as the _env path in the Installer.
114 key = executable, index_url, tuple(find_links)178 key = executable, index_url, tuple(find_links)
115 index = _indexes.get(key)179 index = _indexes.get(key)
116 if index is not None:180 if index is not None:
@@ -119,7 +183,8 @@
119 if index_url is None:183 if index_url is None:
120 index_url = default_index_url184 index_url = default_index_url
121 index = AllowHostsPackageIndex(185 index = AllowHostsPackageIndex(
122 index_url, hosts=allow_hosts, python=_get_version(executable)186 index_url, hosts=allow_hosts, search_path=path,
187 python=_get_version(executable)
123 )188 )
124189
125 if find_links:190 if find_links:
@@ -216,6 +281,8 @@
216 _use_dependency_links = True281 _use_dependency_links = True
217 _allow_picked_versions = True282 _allow_picked_versions = True
218 _always_unzip = False283 _always_unzip = False
284 _include_site_packages = True
285 _allowed_eggs_from_site_packages = ('*',)
219286
220 def __init__(self,287 def __init__(self,
221 dest=None,288 dest=None,
@@ -227,7 +294,9 @@
227 newest=True,294 newest=True,
228 versions=None,295 versions=None,
229 use_dependency_links=None,296 use_dependency_links=None,
230 allow_hosts=('*',)297 allow_hosts=('*',),
298 include_site_packages=None,
299 allowed_eggs_from_site_packages=None
231 ):300 ):
232 self._dest = dest301 self._dest = dest
233 self._allow_hosts = allow_hosts302 self._allow_hosts = allow_hosts
@@ -249,7 +318,28 @@
249 self._executable = executable318 self._executable = executable
250 if always_unzip is not None:319 if always_unzip is not None:
251 self._always_unzip = always_unzip320 self._always_unzip = always_unzip
252 path = (path and path[:] or []) + buildout_and_setuptools_path321 path = (path and path[:] or [])
322 if include_site_packages is not None:
323 self._include_site_packages = include_site_packages
324 if allowed_eggs_from_site_packages is not None:
325 self._allowed_eggs_from_site_packages = tuple(
326 allowed_eggs_from_site_packages)
327 stdlib, self._site_packages = _get_system_paths(executable)
328 version_info = _get_version_info(executable)
329 if version_info == sys.version_info:
330 # Maybe we can add the buildout and setuptools path. If we
331 # are including site_packages, we only have to include the extra
332 # bits here, so we don't duplicate. On the other hand, if we
333 # are not including site_packages, we only want to include the
334 # parts that are not in site_packages, so the code is the same.
335 path.extend(
336 set(buildout_and_setuptools_path).difference(
337 self._site_packages))
338 if self._include_site_packages:
339 path.extend(self._site_packages)
340 # else we could try to still include the buildout_and_setuptools_path
341 # if the elements are not in site_packages, but we're not bothering
342 # with this optimization for now, in the name of code simplicity.
253 if dest is not None and dest not in path:343 if dest is not None and dest not in path:
254 path.insert(0, dest)344 path.insert(0, dest)
255 self._path = path345 self._path = path
@@ -258,13 +348,42 @@
258 self._newest = newest348 self._newest = newest
259 self._env = pkg_resources.Environment(path,349 self._env = pkg_resources.Environment(path,
260 python=_get_version(executable))350 python=_get_version(executable))
261 self._index = _get_index(executable, index, links, self._allow_hosts)351 self._index = _get_index(executable, index, links, self._allow_hosts,
352 self._path)
262353
263 if versions is not None:354 if versions is not None:
264 self._versions = versions355 self._versions = versions
265356
357 _allowed_eggs_from_site_packages_regex = None
358 def allow_site_package_egg(self, name):
359 if (not self._include_site_packages or
360 not self._allowed_eggs_from_site_packages):
361 # If the answer is a blanket "no," perform a shortcut.
362 return False
363 if self._allowed_eggs_from_site_packages_regex is None:
364 pattern = '(%s)' % (
365 '|'.join(
366 fnmatch.translate(name)
367 for name in self._allowed_eggs_from_site_packages),
368 )
369 self._allowed_eggs_from_site_packages_regex = re.compile(pattern)
370 return bool(self._allowed_eggs_from_site_packages_regex.match(name))
371
266 def _satisfied(self, req, source=None):372 def _satisfied(self, req, source=None):
267 dists = [dist for dist in self._env[req.project_name] if dist in req]373 # We get all distributions that match the given requirement. If we are
374 # not supposed to include site-packages for the given egg, we also
375 # filter those out. Even if include_site_packages is False and so we
376 # have excluded site packages from the _env's paths (see
377 # Installer.__init__), we need to do the filtering here because an
378 # .egg-link, such as one for setuptools or zc.buildout installed by
379 # zc.buildout.buildout.Buildout.bootstrap, can indirectly include a
380 # path in our _site_packages.
381 dists = [dist for dist in self._env[req.project_name] if (
382 dist in req and (
383 dist.location not in self._site_packages or
384 self.allow_site_package_egg(dist.project_name))
385 )
386 ]
268 if not dists:387 if not dists:
269 logger.debug('We have no distributions for %s that satisfies %r.',388 logger.debug('We have no distributions for %s that satisfies %r.',
270 req.project_name, str(req))389 req.project_name, str(req))
@@ -465,14 +584,22 @@
465 # Nothing is available.584 # Nothing is available.
466 return None585 return None
467586
468 # Filter the available dists for the requirement and source flag587 # Filter the available dists for the requirement and source flag. If
469 dists = [dist for dist in index[requirement.project_name]588 # we are not supposed to include site-packages for the given egg, we
470 if ((dist in requirement)589 # also filter those out. Even if include_site_packages is False and so
471 and590 # we have excluded site packages from the _env's paths (see
472 ((not source) or591 # Installer.__init__), we need to do the filtering here because an
473 (dist.precedence == pkg_resources.SOURCE_DIST)592 # .egg-link, such as one for setuptools or zc.buildout installed by
474 )593 # zc.buildout.buildout.Buildout.bootstrap, can indirectly include a
475 )594 # path in our _site_packages.
595 dists = [dist for dist in index[requirement.project_name] if (
596 dist in requirement and (
597 dist.location not in self._site_packages or
598 self.allow_site_package_egg(dist.project_name))
599 and (
600 (not source) or
601 (dist.precedence == pkg_resources.SOURCE_DIST))
602 )
476 ]603 ]
477604
478 # If we prefer final dists, filter for final and use the605 # If we prefer final dists, filter for final and use the
@@ -632,7 +759,7 @@
632 self._links.append(link)759 self._links.append(link)
633 self._index = _get_index(self._executable,760 self._index = _get_index(self._executable,
634 self._index_url, self._links,761 self._index_url, self._links,
635 self._allow_hosts)762 self._allow_hosts, self._path)
636763
637 for dist in dists:764 for dist in dists:
638 # Check whether we picked a version and, if we did, report it:765 # Check whether we picked a version and, if we did, report it:
@@ -713,35 +840,52 @@
713 self._maybe_add_setuptools(ws, dist)840 self._maybe_add_setuptools(ws, dist)
714841
715 # OK, we have the requested distributions and they're in the working842 # OK, we have the requested distributions and they're in the working
716 # set, but they may have unmet requirements. We'll simply keep843 # set, but they may have unmet requirements. We'll resolve these
717 # trying to resolve requirements, adding missing requirements as they844 # requirements. This is code modified from
718 # are reported.845 # pkg_resources.WorkingSet.resolve. We can't reuse that code directly
719 #846 # because we have to constrain our requirements (see
720 # Note that we don't pass in the environment, because we want847 # versions_section_ignored_for_dependency_in_favor_of_site_packages in
848 # zc.buildout.tests).
849 requirements.reverse() # Set up the stack.
850 processed = {} # This is a set of processed requirements.
851 best = {} # This is a mapping of key -> dist.
852 # Note that we don't use the existing environment, because we want
721 # to look for new eggs unless what we have is the best that853 # to look for new eggs unless what we have is the best that
722 # matches the requirement.854 # matches the requirement.
723 while 1:855 env = pkg_resources.Environment(ws.entries)
724 try:856 while requirements:
725 ws.resolve(requirements)857 # Process dependencies breadth-first.
726 except pkg_resources.DistributionNotFound, err:858 req = self._constrain(requirements.pop(0))
727 [requirement] = err859 if req in processed:
728 requirement = self._constrain(requirement)860 # Ignore cyclic or redundant dependencies.
729 if destination:861 continue
730 logger.debug('Getting required %r', str(requirement))862 dist = best.get(req.key)
731 else:863 if dist is None:
732 logger.debug('Adding required %r', str(requirement))864 # Find the best distribution and add it to the map.
733 _log_requirement(ws, requirement)865 dist = ws.by_key.get(req.key)
734866 if dist is None:
735 for dist in self._get_dist(requirement, ws, self._always_unzip867 try:
736 ):868 dist = best[req.key] = env.best_match(req, ws)
737869 except pkg_resources.VersionConflict, err:
738 ws.add(dist)870 raise VersionConflict(err, ws)
739 self._maybe_add_setuptools(ws, dist)871 if dist is None:
740 except pkg_resources.VersionConflict, err:872 if destination:
741 raise VersionConflict(err, ws)873 logger.debug('Getting required %r', str(req))
742 else:874 else:
743 break875 logger.debug('Adding required %r', str(req))
744876 _log_requirement(ws, req)
877 for dist in self._get_dist(req,
878 ws, self._always_unzip):
879 ws.add(dist)
880 self._maybe_add_setuptools(ws, dist)
881 if dist not in req:
882 # Oops, the "best" so far conflicts with a dependency.
883 raise VersionConflict(
884 pkg_resources.VersionConflict(dist, req), ws)
885 requirements.extend(dist.requires(req.extras)[::-1])
886 processed[req] = True
887 if dist.location in self._site_packages:
888 logger.debug('Egg from site-packages: %s', dist)
745 return ws889 return ws
746890
747 def build(self, spec, build_ext):891 def build(self, spec, build_ext):
@@ -836,6 +980,18 @@
836 Installer._prefer_final = bool(setting)980 Installer._prefer_final = bool(setting)
837 return old981 return old
838982
983def include_site_packages(setting=None):
984 old = Installer._include_site_packages
985 if setting is not None:
986 Installer._include_site_packages = bool(setting)
987 return old
988
989def allowed_eggs_from_site_packages(setting=None):
990 old = Installer._allowed_eggs_from_site_packages
991 if setting is not None:
992 Installer._allowed_eggs_from_site_packages = tuple(setting)
993 return old
994
839def use_dependency_links(setting=None):995def use_dependency_links(setting=None):
840 old = Installer._use_dependency_links996 old = Installer._use_dependency_links
841 if setting is not None:997 if setting is not None:
@@ -858,19 +1014,27 @@
858 links=(), index=None,1014 links=(), index=None,
859 executable=sys.executable, always_unzip=None,1015 executable=sys.executable, always_unzip=None,
860 path=None, working_set=None, newest=True, versions=None,1016 path=None, working_set=None, newest=True, versions=None,
861 use_dependency_links=None, allow_hosts=('*',)):1017 use_dependency_links=None, allow_hosts=('*',),
1018 include_site_packages=None, allowed_eggs_from_site_packages=None):
862 installer = Installer(dest, links, index, executable, always_unzip, path,1019 installer = Installer(dest, links, index, executable, always_unzip, path,
863 newest, versions, use_dependency_links,1020 newest, versions, use_dependency_links,
864 allow_hosts=allow_hosts)1021 allow_hosts=allow_hosts,
1022 include_site_packages=include_site_packages,
1023 allowed_eggs_from_site_packages=
1024 allowed_eggs_from_site_packages)
865 return installer.install(specs, working_set)1025 return installer.install(specs, working_set)
8661026
8671027
868def build(spec, dest, build_ext,1028def build(spec, dest, build_ext,
869 links=(), index=None,1029 links=(), index=None,
870 executable=sys.executable,1030 executable=sys.executable,
871 path=None, newest=True, versions=None, allow_hosts=('*',)):1031 path=None, newest=True, versions=None, allow_hosts=('*',),
1032 include_site_packages=None, allowed_eggs_from_site_packages=None):
872 installer = Installer(dest, links, index, executable, True, path, newest,1033 installer = Installer(dest, links, index, executable, True, path, newest,
873 versions, allow_hosts=allow_hosts)1034 versions, allow_hosts=allow_hosts,
1035 include_site_packages=include_site_packages,
1036 allowed_eggs_from_site_packages=
1037 allowed_eggs_from_site_packages)
874 return installer.build(spec, build_ext)1038 return installer.build(spec, build_ext)
8751039
8761040
@@ -965,9 +1129,12 @@
965 undo.reverse()1129 undo.reverse()
966 [f() for f in undo]1130 [f() for f in undo]
9671131
9681132def working_set(specs, executable, path, include_site_packages=None,
969def working_set(specs, executable, path):1133 allowed_eggs_from_site_packages=None):
970 return install(specs, None, executable=executable, path=path)1134 return install(
1135 specs, None, executable=executable, path=path,
1136 include_site_packages=include_site_packages,
1137 allowed_eggs_from_site_packages=allowed_eggs_from_site_packages)
9711138
972############################################################################1139############################################################################
973# Script generation functions1140# Script generation functions
@@ -1002,7 +1169,7 @@
1002def sitepackage_safe_scripts(1169def sitepackage_safe_scripts(
1003 dest, working_set, executable, site_py_dest,1170 dest, working_set, executable, site_py_dest,
1004 reqs=(), scripts=None, interpreter=None, extra_paths=(),1171 reqs=(), scripts=None, interpreter=None, extra_paths=(),
1005 initialization='', add_site_packages=False, exec_sitecustomize=False,1172 initialization='', include_site_packages=False, exec_sitecustomize=False,
1006 relative_paths=False, script_arguments='', script_initialization=''):1173 relative_paths=False, script_arguments='', script_initialization=''):
1007 """Generate scripts and/or an interpreter from a system Python.1174 """Generate scripts and/or an interpreter from a system Python.
10081175
@@ -1016,7 +1183,7 @@
1016 site_py_dest, executable, initialization, exec_sitecustomize))1183 site_py_dest, executable, initialization, exec_sitecustomize))
1017 generated.append(_generate_site(1184 generated.append(_generate_site(
1018 site_py_dest, working_set, executable, extra_paths,1185 site_py_dest, working_set, executable, extra_paths,
1019 add_site_packages, relative_paths))1186 include_site_packages, relative_paths))
1020 script_initialization = (1187 script_initialization = (
1021 '\nimport site # imports custom buildout-generated site.py\n%s' % (1188 '\nimport site # imports custom buildout-generated site.py\n%s' % (
1022 script_initialization,))1189 script_initialization,))
@@ -1301,54 +1468,6 @@
13011468
1302# These are used only by the newer ``sitepackage_safe_scripts`` function.1469# These are used only by the newer ``sitepackage_safe_scripts`` function.
13031470
1304def _get_system_paths(executable):
1305 """Return lists of standard lib and site paths for executable.
1306 """
1307 # We want to get a list of the site packages, which is not easy.
1308 # The canonical way to do this is to use
1309 # distutils.sysconfig.get_python_lib(), but that only returns a
1310 # single path, which does not reflect reality for many system
1311 # Pythons, which have multiple additions. Instead, we start Python
1312 # with -S, which does not import site.py and set up the extra paths
1313 # like site-packages or (Ubuntu/Debian) dist-packages and
1314 # python-support. We then compare that sys.path with the normal one
1315 # (minus user packages if this is Python 2.6, because we don't
1316 # support those (yet?). The set of the normal one minus the set of
1317 # the ones in ``python -S`` is the set of packages that are
1318 # effectively site-packages.
1319 #
1320 # The given executable might not be the current executable, so it is
1321 # appropriate to do another subprocess to figure out what the
1322 # additional site-package paths are. Moreover, even if this
1323 # executable *is* the current executable, this code might be run in
1324 # the context of code that has manipulated the sys.path--for
1325 # instance, to add local zc.buildout or setuptools eggs.
1326 def get_sys_path(*args, **kwargs):
1327 cmd = [executable]
1328 cmd.extend(args)
1329 cmd.extend([
1330 "-c", "import sys, os;"
1331 "print repr([os.path.normpath(p) for p in sys.path if p])"])
1332 # Windows needs some (as yet to be determined) part of the real env.
1333 env = os.environ.copy()
1334 env.update(kwargs)
1335 _proc = subprocess.Popen(
1336 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
1337 stdout, stderr = _proc.communicate();
1338 if _proc.returncode:
1339 raise RuntimeError(
1340 'error trying to get system packages:\n%s' % (stderr,))
1341 res = eval(stdout.strip())
1342 try:
1343 res.remove('.')
1344 except ValueError:
1345 pass
1346 return res
1347 stdlib = get_sys_path('-S') # stdlib only
1348 no_user_paths = get_sys_path(PYTHONNOUSERSITE='x')
1349 site_paths = [p for p in no_user_paths if p not in stdlib]
1350 return (stdlib, site_paths)
1351
1352def _get_module_file(executable, name):1471def _get_module_file(executable, name):
1353 """Return a module's file path.1472 """Return a module's file path.
13541473
@@ -1401,10 +1520,10 @@
1401 return sitecustomize_path1520 return sitecustomize_path
14021521
1403def _generate_site(dest, working_set, executable, extra_paths=(),1522def _generate_site(dest, working_set, executable, extra_paths=(),
1404 add_site_packages=False, relative_paths=False):1523 include_site_packages=False, relative_paths=False):
1405 """Write a site.py file with eggs from working_set.1524 """Write a site.py file with eggs from working_set.
14061525
1407 extra_paths will be added to the path. If add_site_packages is True,1526 extra_paths will be added to the path. If include_site_packages is True,
1408 paths from the underlying Python will be added.1527 paths from the underlying Python will be added.
1409 """1528 """
1410 path = _get_path(working_set, extra_paths)1529 path = _get_path(working_set, extra_paths)
@@ -1416,7 +1535,7 @@
1416 [(line and ' %s' % (line,) or line)1535 [(line and ' %s' % (line,) or line)
1417 for line in preamble.split('\n')])1536 for line in preamble.split('\n')])
1418 original_path_setup = ''1537 original_path_setup = ''
1419 if add_site_packages:1538 if include_site_packages:
1420 stdlib, site_paths = _get_system_paths(executable)1539 stdlib, site_paths = _get_system_paths(executable)
1421 original_path_setup = original_path_snippet % (1540 original_path_setup = original_path_snippet % (
1422 _format_paths((repr(p) for p in site_paths), 2),)1541 _format_paths((repr(p) for p in site_paths), 2),)
@@ -1431,7 +1550,7 @@
1431 relative_paths)1550 relative_paths)
1432 else:1551 else:
1433 location = repr(distribution.location)1552 location = repr(distribution.location)
1434 preamble += namespace_add_site_packages_setup % (location,)1553 preamble += namespace_include_site_packages_setup % (location,)
1435 original_path_setup = (1554 original_path_setup = (
1436 addsitedir_namespace_originalpackages_snippet +1555 addsitedir_namespace_originalpackages_snippet +
1437 original_path_setup)1556 original_path_setup)
@@ -1460,7 +1579,7 @@
1460 raise RuntimeError('Buildout did not successfully rewrite site.py')1579 raise RuntimeError('Buildout did not successfully rewrite site.py')
1461 return site_path1580 return site_path
14621581
1463namespace_add_site_packages_setup = '''1582namespace_include_site_packages_setup = '''
1464 setuptools_path = %s1583 setuptools_path = %s
1465 sys.path.append(setuptools_path)1584 sys.path.append(setuptools_path)
1466 known_paths.add(os.path.normcase(setuptools_path))1585 known_paths.add(os.path.normcase(setuptools_path))
14671586
=== modified file 'src/zc/buildout/easy_install.txt'
--- src/zc/buildout/easy_install.txt 2010-02-24 23:22:13 +0000
+++ src/zc/buildout/easy_install.txt 2010-02-24 23:22:13 +0000
@@ -89,6 +89,14 @@
89 for using dependency_links in preference to other89 for using dependency_links in preference to other
90 locations. Defaults to true.90 locations. Defaults to true.
9191
92include_site_packages
93 A flag indicating whether Python's non-standard-library packages should
94 be available for finding dependencies. Defaults to true.
95
96 Paths outside of Python's standard library--or more precisely, those that
97 are not included when Python is started with the -S argument--are loosely
98 referred to as "site-packages" here.
99
92relative_paths100relative_paths
93 Adjust egg paths so they are relative to the script path. This101 Adjust egg paths so they are relative to the script path. This
94 allows scripts to work when scripts and eggs are moved, as long as102 allows scripts to work when scripts and eggs are moved, as long as
@@ -399,6 +407,68 @@
399 >>> [d.version for d in ws]407 >>> [d.version for d in ws]
400 ['0.3', '1.1']408 ['0.3', '1.1']
401409
410Dependencies in Site Packages
411-----------------------------
412
413Paths outside of Python's standard library--or more precisely, those that are
414not included when Python is started with the -S argument--are loosely referred
415to as "site-packages" here. These site-packages are searched by default for
416distributions. This can be disabled, so that, for instance, a system Python
417can be used with buildout, cleaned of any packages installed by a user or
418system package manager.
419
420The default behavior can be controlled and introspected using
421zc.buildout.easy_install.include_site_packages.
422
423 >>> zc.buildout.easy_install.include_site_packages()
424 True
425
426Here's an example of using a Python executable that includes our dependencies.
427
428Our "py_path" will have the "demoneeded," and "demo" packages available.
429 We'll simply be asking for "demoneeded" here, but without any external
430 index or links.
431
432 >>> from zc.buildout.tests import create_sample_sys_install
433 >>> py_path, site_packages_path = make_py()
434 >>> create_sample_sys_install(site_packages_path)
435
436 >>> example_dest = tmpdir('site-packages-example-install')
437 >>> workingset = zc.buildout.easy_install.install(
438 ... ['demoneeded'], example_dest, links=[], executable=py_path,
439 ... index=None)
440 >>> [dist.project_name for dist in workingset]
441 ['demoneeded']
442
443That worked fine. Let's try again with site packages not allowed. We'll
444change the policy by changing the default. Notice that the function for
445changing the default value returns the previous value.
446
447 >>> zc.buildout.easy_install.include_site_packages(False)
448 True
449
450 >>> zc.buildout.easy_install.include_site_packages()
451 False
452
453 >>> zc.buildout.easy_install.clear_index_cache()
454 >>> rmdir(example_dest)
455 >>> example_dest = tmpdir('site-packages-example-install')
456 >>> workingset = zc.buildout.easy_install.install(
457 ... ['demoneeded'], example_dest, links=[], executable=py_path,
458 ... index=None)
459 Traceback (most recent call last):
460 ...
461 MissingDistribution: Couldn't find a distribution for 'demoneeded'.
462 >>> zc.buildout.easy_install.clear_index_cache()
463
464Now we'll reset the default.
465
466 >>> zc.buildout.easy_install.include_site_packages(True)
467 False
468
469 >>> zc.buildout.easy_install.include_site_packages()
470 True
471
402Dependency links472Dependency links
403----------------473----------------
404474
@@ -1197,7 +1267,7 @@
1197 >>> reset_interpreter()1267 >>> reset_interpreter()
1198 >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(1268 >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
1199 ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,1269 ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
1200 ... interpreter='py', add_site_packages=True)1270 ... interpreter='py', include_site_packages=True)
1201 >>> sys.stdout.write('#\n'); cat(site_path)1271 >>> sys.stdout.write('#\n'); cat(site_path)
1202 ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE1272 ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
1203 #...1273 #...
@@ -1266,7 +1336,7 @@
1266 ... links=[link_server, namespace_eggs], index=link_server+'index/')1336 ... links=[link_server, namespace_eggs], index=link_server+'index/')
1267 >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(1337 >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
1268 ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,1338 ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
1269 ... interpreter='py', add_site_packages=True)1339 ... interpreter='py', include_site_packages=True)
1270 >>> sys.stdout.write('#\n'); cat(site_path)1340 >>> sys.stdout.write('#\n'); cat(site_path)
1271 ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE1341 ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
1272 #...1342 #...
@@ -1324,7 +1394,7 @@
1324 >>> reset_interpreter()1394 >>> reset_interpreter()
1325 >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(1395 >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
1326 ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,1396 ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
1327 ... interpreter='py', add_site_packages=True,1397 ... interpreter='py', include_site_packages=True,
1328 ... relative_paths=interpreter_dir)1398 ... relative_paths=interpreter_dir)
1329 >>> sys.stdout.write('#\n'); cat(site_path)1399 >>> sys.stdout.write('#\n'); cat(site_path)
1330 ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE1400 ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
13311401
=== modified file 'src/zc/buildout/testing.py'
--- src/zc/buildout/testing.py 2010-02-24 23:22:13 +0000
+++ src/zc/buildout/testing.py 2010-02-24 23:22:13 +0000
@@ -222,11 +222,37 @@
222 time.sleep(0.01)222 time.sleep(0.01)
223 raise ValueError('Timed out waiting for: '+label)223 raise ValueError('Timed out waiting for: '+label)
224224
225def get_installer_values():
226 """Get the current values for the easy_install module.
227
228 This is necessary because instantiating a Buildout will force the
229 Buildout's values on the installer.
230
231 Returns a dict of names-values suitable for set_installer_values."""
232 names = ('default_versions', 'download_cache', 'install_from_cache',
233 'prefer_final', 'include_site_packages',
234 'allowed_eggs_from_site_packages', 'use_dependency_links',
235 'allow_picked_versions', 'always_unzip'
236 )
237 values = {}
238 for name in names:
239 values[name] = getattr(zc.buildout.easy_install, name)()
240 return values
241
242def set_installer_values(values):
243 """Set the given values on the installer."""
244 for name, value in values.items():
245 getattr(zc.buildout.easy_install, name)(value)
246
225def make_buildout():247def make_buildout():
226 # Create a basic buildout.cfg to avoid a warning from buildout:248 """Make a buildout that uses this version of zc.buildout."""
249 # Create a basic buildout.cfg to avoid a warning from buildout.
227 open('buildout.cfg', 'w').write(250 open('buildout.cfg', 'w').write(
228 "[buildout]\nparts =\n"251 "[buildout]\nparts =\n"
229 )252 )
253 # Get state of installer defaults so we can reinstate them (instantiating
254 # a Buildout will force the Buildout's defaults on the installer).
255 installer_values = get_installer_values()
230 # Use the buildout bootstrap command to create a buildout256 # Use the buildout bootstrap command to create a buildout
231 zc.buildout.buildout.Buildout(257 zc.buildout.buildout.Buildout(
232 'buildout.cfg',258 'buildout.cfg',
@@ -234,20 +260,23 @@
234 # trick bootstrap into putting the buildout develop egg260 # trick bootstrap into putting the buildout develop egg
235 # in the eggs dir.261 # in the eggs dir.
236 ('buildout', 'develop-eggs-directory', 'eggs'),262 ('buildout', 'develop-eggs-directory', 'eggs'),
237 ]263 ],
264 user_defaults=False,
238 ).bootstrap([])265 ).bootstrap([])
239 # Create the develop-eggs dir, which didn't get created the usual266 # Create the develop-eggs dir, which didn't get created the usual
240 # way due to the trick above:267 # way due to the trick above:
241 os.mkdir('develop-eggs')268 os.mkdir('develop-eggs')
269 # Reinstate the default values of the installer.
270 set_installer_values(installer_values)
242271
243def buildoutSetUp(test):272def buildoutSetUp(test):
244273
245 test.globs['__tear_downs'] = __tear_downs = []274 test.globs['__tear_downs'] = __tear_downs = []
246 test.globs['register_teardown'] = register_teardown = __tear_downs.append275 test.globs['register_teardown'] = register_teardown = __tear_downs.append
247276
248 prefer_final = zc.buildout.easy_install.prefer_final()277 installer_values = get_installer_values()
249 register_teardown(278 register_teardown(
250 lambda: zc.buildout.easy_install.prefer_final(prefer_final)279 lambda: set_installer_values(installer_values)
251 )280 )
252281
253 here = os.getcwd()282 here = os.getcwd()
@@ -367,8 +396,6 @@
367 make_py = make_py396 make_py = make_py
368 ))397 ))
369398
370 zc.buildout.easy_install.prefer_final(prefer_final)
371
372def buildoutTearDown(test):399def buildoutTearDown(test):
373 for f in test.globs['__tear_downs']:400 for f in test.globs['__tear_downs']:
374 f()401 f()
375402
=== modified file 'src/zc/buildout/tests.py'
--- src/zc/buildout/tests.py 2010-02-24 23:22:13 +0000
+++ src/zc/buildout/tests.py 2010-02-24 23:22:13 +0000
@@ -385,6 +385,64 @@
385 Error: Couldn't find a distribution for 'demoneeded'.385 Error: Couldn't find a distribution for 'demoneeded'.
386 """386 """
387387
388def show_eggs_from_site_packages():
389 """
390Sometimes you want to know what eggs are coming from site-packages. This
391might be for a diagnostic, or so that you can get a starting value for the
392allowed-eggs-from-site-packages option. The -v flag will also include this
393information.
394
395Our "py_path" has the "demoneeded," "demo"
396packages available. We'll ask for "bigdemo," which will get both of them.
397
398Here's our set up.
399
400 >>> py_path, site_packages_path = make_py()
401 >>> create_sample_sys_install(site_packages_path)
402
403 >>> write('buildout.cfg',
404 ... '''
405 ... [buildout]
406 ... parts = eggs
407 ... prefer-final = true
408 ... find-links = %(link_server)s
409 ...
410 ... [primed_python]
411 ... executable = %(py_path)s
412 ...
413 ... [eggs]
414 ... recipe = zc.recipe.egg:eggs
415 ... python = primed_python
416 ... eggs = bigdemo
417 ... ''' % globals())
418
419Now here is the output. The lines that begin with "Egg from site-packages:"
420indicate the eggs from site-packages that have been selected. You'll see
421we have two: demo 0.3 and demoneeded 1.1.
422
423 >>> print system(py_path+" "+buildout+" -v")
424 Installing 'zc.buildout', 'setuptools'.
425 We have a develop egg: zc.buildout V
426 We have the best distribution that satisfies 'setuptools'.
427 Picked: setuptools = V
428 Installing 'zc.recipe.egg'.
429 We have a develop egg: zc.recipe.egg V
430 Installing eggs.
431 Installing 'bigdemo'.
432 We have no distributions for bigdemo that satisfies 'bigdemo'.
433 Getting distribution for 'bigdemo'.
434 Got bigdemo 0.1.
435 Picked: bigdemo = 0.1
436 Getting required 'demo'
437 required by bigdemo 0.1.
438 We have a develop egg: demo V
439 Egg from site-packages: demo 0.3
440 Getting required 'demoneeded'
441 required by demo 0.3.
442 We have a develop egg: demoneeded V
443 Egg from site-packages: demoneeded 1.1
444 <BLANKLINE>
445 """
388446
389def test_comparing_saved_options_with_funny_characters():447def test_comparing_saved_options_with_funny_characters():
390 """448 """
@@ -1854,7 +1912,7 @@
1854 ... recipe = z3c.recipe.scripts1912 ... recipe = z3c.recipe.scripts
1855 ... python = primed_python1913 ... python = primed_python
1856 ... interpreter = py1914 ... interpreter = py
1857 ... add-site-packages = true1915 ... include-site-packages = true
1858 ... eggs = tellmy.version == 1.01916 ... eggs = tellmy.version == 1.0
1859 ... tellmy.fortune == 1.01917 ... tellmy.fortune == 1.0
1860 ... demo1918 ... demo
@@ -1879,7 +1937,7 @@
1879 Generated interpreter '/sample-buildout/bin/py'.1937 Generated interpreter '/sample-buildout/bin/py'.
1880 <BLANKLINE>1938 <BLANKLINE>
18811939
1882Finally, we are ready for the actual test. Prior to the bug fix that1940Finally, we are ready to see if it worked. Prior to the bug fix that
1883this tests, the results of both calls below was the following::1941this tests, the results of both calls below was the following::
18841942
1885 1.11943 1.1
@@ -2005,6 +2063,197 @@
20052063
2006 """2064 """
20072065
2066def isolated_include_site_packages():
2067 """
2068
2069This is an isolated test of the include_site_packages functionality, passing
2070the argument directly to install, overriding a default.
2071
2072Our "py_path" has the "demoneeded" and "demo" packages available. We'll
2073simply be asking for "demoneeded" here.
2074
2075 >>> py_path, site_packages_path = make_py()
2076 >>> create_sample_sys_install(site_packages_path)
2077 >>> zc.buildout.easy_install.include_site_packages(False)
2078 True
2079
2080 >>> example_dest = tmpdir('site-packages-example-install')
2081 >>> workingset = zc.buildout.easy_install.install(
2082 ... ['demoneeded'], example_dest, links=[], executable=py_path,
2083 ... index=None, include_site_packages=True)
2084 >>> [dist.project_name for dist in workingset]
2085 ['demoneeded']
2086
2087That worked fine. Let's try again with site packages not allowed (and
2088reversing the default).
2089
2090 >>> zc.buildout.easy_install.include_site_packages(True)
2091 False
2092
2093 >>> zc.buildout.easy_install.clear_index_cache()
2094 >>> rmdir(example_dest)
2095 >>> example_dest = tmpdir('site-packages-example-install')
2096 >>> workingset = zc.buildout.easy_install.install(
2097 ... ['demoneeded'], example_dest, links=[], executable=py_path,
2098 ... index=None, include_site_packages=False)
2099 Traceback (most recent call last):
2100 ...
2101 MissingDistribution: Couldn't find a distribution for 'demoneeded'.
2102
2103That's a failure, as expected.
2104
2105Now we explore an important edge case.
2106
2107Some system Pythons include setuptools (and other Python packages) in their
2108site-packages (or equivalent) using a .egg-info directory. The pkg_resources
2109module (from setuptools) considers a package installed using .egg-info to be a
2110develop egg.
2111
2112zc.buildout.buildout.Buildout.bootstrap will make setuptools and zc.buildout
2113available to the buildout via the eggs directory, for normal eggs; or the
2114develop-eggs directory, for develop-eggs.
2115
2116If setuptools or zc.buildout is found in site-packages and considered by
2117pkg_resources to be a develop egg, then the bootstrap code will use a .egg-link
2118in the local develop-eggs, pointing to site-packages, in its entirety. Because
2119develop-eggs must always be available for searching for distributions, this
2120indirectly brings site-packages back into the search path for distributions.
2121
2122Because of this, we have to take special care that we still exclude
2123site-packages even in this case. See the comments about site packages in the
2124Installer._satisfied and Installer._obtain methods for the implementation
2125(as of this writing).
2126
2127In this demonstration, we insert a link to the "demoneeded" distribution
2128in our develop-eggs, which would bring the package back in, except for
2129the special care we have taken to exclude it.
2130
2131 >>> zc.buildout.easy_install.clear_index_cache()
2132 >>> rmdir(example_dest)
2133 >>> example_dest = tmpdir('site-packages-example-install')
2134 >>> mkdir(example_dest, 'develop-eggs')
2135 >>> write(example_dest, 'develop-eggs', 'demoneeded.egg-link',
2136 ... site_packages_path)
2137 >>> workingset = zc.buildout.easy_install.install(
2138 ... ['demoneeded'], example_dest, links=[],
2139 ... path=[join(example_dest, 'develop-eggs')],
2140 ... executable=py_path,
2141 ... index=None, include_site_packages=False)
2142 Traceback (most recent call last):
2143 ...
2144 MissingDistribution: Couldn't find a distribution for 'demoneeded'.
2145
2146The MissingDistribution error shows that buildout correctly excluded the
2147"site-packages" source even though it was indirectly included in the path
2148via a .egg-link file.
2149
2150 """
2151
2152def allowed_eggs_from_site_packages():
2153 """
2154Sometimes you need or want to control what eggs from site-packages are used.
2155The allowed-eggs-from-site-packages option allows you to specify a whitelist of
2156project names that may be included from site-packages. You can use globs to
2157specify the value. It defaults to a single value of '*', indicating that any
2158package may come from site-packages.
2159
2160This option interacts with include-site-packages in the following ways.
2161
2162If include-site-packages is true, then allowed-eggs-from-site-packages filters
2163what eggs from site-packages may be chosen. If allowed-eggs-from-site-packages
2164is an empty list, then no eggs from site-packages are chosen, but site-packages
2165will still be included at the end of path lists.
2166
2167If include-site-packages is false, allowed-eggs-from-site-packages is
2168irrelevant.
2169
2170This test shows the interaction with the zc.buildout.easy_install API. Another
2171test below (allow_site_package_eggs_option) shows using it with a buildout.cfg.
2172
2173Our "py_path" has the "demoneeded" and "demo" packages available. We'll
2174simply be asking for "demoneeded" here.
2175
2176 >>> py_path, site_packages_path = make_py()
2177 >>> create_sample_sys_install(site_packages_path)
2178
2179 >>> example_dest = tmpdir('site-packages-example-install')
2180 >>> workingset = zc.buildout.easy_install.install(
2181 ... ['demoneeded'], example_dest, links=[], executable=py_path,
2182 ... index=None,
2183 ... allowed_eggs_from_site_packages=['demoneeded', 'other'])
2184 >>> [dist.project_name for dist in workingset]
2185 ['demoneeded']
2186
2187That worked fine. It would work fine for a glob too.
2188
2189 >>> zc.buildout.easy_install.clear_index_cache()
2190 >>> rmdir(example_dest)
2191 >>> example_dest = tmpdir('site-packages-example-install')
2192 >>> workingset = zc.buildout.easy_install.install(
2193 ... ['demoneeded'], example_dest, links=[], executable=py_path,
2194 ... index=None,
2195 ... allowed_eggs_from_site_packages=['?emon*', 'other'])
2196 >>> [dist.project_name for dist in workingset]
2197 ['demoneeded']
2198
2199But now let's try again with 'demoneeded' not allowed.
2200
2201 >>> zc.buildout.easy_install.clear_index_cache()
2202 >>> rmdir(example_dest)
2203 >>> example_dest = tmpdir('site-packages-example-install')
2204 >>> workingset = zc.buildout.easy_install.install(
2205 ... ['demoneeded'], example_dest, links=[], executable=py_path,
2206 ... index=None,
2207 ... allowed_eggs_from_site_packages=['demo'])
2208 Traceback (most recent call last):
2209 ...
2210 MissingDistribution: Couldn't find a distribution for 'demoneeded'.
2211
2212Here's the same, but with an empty list.
2213
2214 >>> zc.buildout.easy_install.clear_index_cache()
2215 >>> rmdir(example_dest)
2216 >>> example_dest = tmpdir('site-packages-example-install')
2217 >>> workingset = zc.buildout.easy_install.install(
2218 ... ['demoneeded'], example_dest, links=[], executable=py_path,
2219 ... index=None,
2220 ... allowed_eggs_from_site_packages=[])
2221 Traceback (most recent call last):
2222 ...
2223 MissingDistribution: Couldn't find a distribution for 'demoneeded'.
2224
2225Of course, this doesn't stop us from getting a package from elsewhere. Here,
2226we add a link server.
2227
2228 >>> zc.buildout.easy_install.clear_index_cache()
2229 >>> rmdir(example_dest)
2230 >>> example_dest = tmpdir('site-packages-example-install')
2231 >>> workingset = zc.buildout.easy_install.install(
2232 ... ['demoneeded'], example_dest, executable=py_path,
2233 ... links=[link_server], index=link_server+'index/',
2234 ... allowed_eggs_from_site_packages=['other'])
2235 >>> [dist.project_name for dist in workingset]
2236 ['demoneeded']
2237 >>> [dist.location for dist in workingset]
2238 ['/site-packages-example-install/demoneeded-1.1-py2.6.egg']
2239
2240Finally, here's an example of an interaction: we say that it is OK to
2241allow the "demoneeded" egg to come from site-packages, but we don't
2242include-site-packages.
2243
2244 >>> zc.buildout.easy_install.clear_index_cache()
2245 >>> rmdir(example_dest)
2246 >>> example_dest = tmpdir('site-packages-example-install')
2247 >>> workingset = zc.buildout.easy_install.install(
2248 ... ['demoneeded'], example_dest, links=[], executable=py_path,
2249 ... index=None, include_site_packages=False,
2250 ... allowed_eggs_from_site_packages=['demoneeded'])
2251 Traceback (most recent call last):
2252 ...
2253 MissingDistribution: Couldn't find a distribution for 'demoneeded'.
2254
2255 """
2256
2008if sys.version_info > (2, 4):2257if sys.version_info > (2, 4):
2009 def test_exit_codes():2258 def test_exit_codes():
2010 """2259 """
@@ -2932,24 +3181,59 @@
2932 finally:3181 finally:
2933 shutil.rmtree(tmp)3182 shutil.rmtree(tmp)
29343183
3184def _write_eggrecipedemoneeded(tmp, minor_version, suffix=''):
3185 from zc.buildout.testing import write
3186 write(tmp, 'README.txt', '')
3187 write(tmp, 'eggrecipedemoneeded.py',
3188 'y=%s\ndef f():\n pass' % minor_version)
3189 write(
3190 tmp, 'setup.py',
3191 "from setuptools import setup\n"
3192 "setup(name='demoneeded', py_modules=['eggrecipedemoneeded'],"
3193 " zip_safe=True, version='1.%s%s', author='bob', url='bob', "
3194 "author_email='bob')\n"
3195 % (minor_version, suffix)
3196 )
3197
3198def _write_eggrecipedemo(tmp, minor_version, suffix=''):
3199 from zc.buildout.testing import write
3200 write(tmp, 'README.txt', '')
3201 write(
3202 tmp, 'eggrecipedemo.py',
3203 'import eggrecipedemoneeded\n'
3204 'x=%s\n'
3205 'def main(): print x, eggrecipedemoneeded.y\n'
3206 % minor_version)
3207 write(
3208 tmp, 'setup.py',
3209 "from setuptools import setup\n"
3210 "setup(name='demo', py_modules=['eggrecipedemo'],"
3211 " install_requires = 'demoneeded',"
3212 " entry_points={'console_scripts': "
3213 "['demo = eggrecipedemo:main']},"
3214 " zip_safe=True, version='0.%s%s')\n" % (minor_version, suffix)
3215 )
3216
3217def create_sample_sys_install(site_packages_path):
3218 for creator, minor_version in (
3219 (_write_eggrecipedemoneeded, 1),
3220 (_write_eggrecipedemo, 3)):
3221 # Write the files and install in site_packages_path.
3222 tmp = tempfile.mkdtemp()
3223 try:
3224 creator(tmp, minor_version)
3225 zc.buildout.testing.sys_install(tmp, site_packages_path)
3226 finally:
3227 shutil.rmtree(tmp)
3228
2935def create_sample_eggs(test, executable=sys.executable):3229def create_sample_eggs(test, executable=sys.executable):
2936 write = test.globs['write']3230 from zc.buildout.testing import write
2937 dest = test.globs['sample_eggs']3231 dest = test.globs['sample_eggs']
2938 tmp = tempfile.mkdtemp()3232 tmp = tempfile.mkdtemp()
2939 try:3233 try:
2940 write(tmp, 'README.txt', '')
2941
2942 for i in (0, 1, 2):3234 for i in (0, 1, 2):
2943 write(tmp, 'eggrecipedemoneeded.py', 'y=%s\ndef f():\n pass' % i)3235 suffix = i==2 and 'c1' or ''
2944 c1 = i==2 and 'c1' or ''3236 _write_eggrecipedemoneeded(tmp, i, suffix)
2945 write(
2946 tmp, 'setup.py',
2947 "from setuptools import setup\n"
2948 "setup(name='demoneeded', py_modules=['eggrecipedemoneeded'],"
2949 " zip_safe=True, version='1.%s%s', author='bob', url='bob', "
2950 "author_email='bob')\n"
2951 % (i, c1)
2952 )
2953 zc.buildout.testing.sdist(tmp, dest)3237 zc.buildout.testing.sdist(tmp, dest)
29543238
2955 write(3239 write(
@@ -2963,22 +3247,8 @@
2963 os.remove(os.path.join(tmp, 'eggrecipedemoneeded.py'))3247 os.remove(os.path.join(tmp, 'eggrecipedemoneeded.py'))
29643248
2965 for i in (1, 2, 3, 4):3249 for i in (1, 2, 3, 4):
2966 write(3250 suffix = i==4 and 'c1' or ''
2967 tmp, 'eggrecipedemo.py',3251 _write_eggrecipedemo(tmp, i, suffix)
2968 'import eggrecipedemoneeded\n'
2969 'x=%s\n'
2970 'def main(): print x, eggrecipedemoneeded.y\n'
2971 % i)
2972 c1 = i==4 and 'c1' or ''
2973 write(
2974 tmp, 'setup.py',
2975 "from setuptools import setup\n"
2976 "setup(name='demo', py_modules=['eggrecipedemo'],"
2977 " install_requires = 'demoneeded',"
2978 " entry_points={'console_scripts': "
2979 "['demo = eggrecipedemo:main']},"
2980 " zip_safe=True, version='0.%s%s')\n" % (i, c1)
2981 )
2982 zc.buildout.testing.bdist_egg(tmp, executable, dest)3252 zc.buildout.testing.bdist_egg(tmp, executable, dest)
29833253
2984 write(tmp, 'eggrecipebigdemo.py', 'import eggrecipedemo')3254 write(tmp, 'eggrecipebigdemo.py', 'import eggrecipedemo')
29853255
=== modified file 'z3c.recipe.scripts_/src/z3c/recipe/scripts/README.txt'
--- z3c.recipe.scripts_/src/z3c/recipe/scripts/README.txt 2010-02-24 23:22:13 +0000
+++ z3c.recipe.scripts_/src/z3c/recipe/scripts/README.txt 2010-02-24 23:22:13 +0000
@@ -33,7 +33,7 @@
33In addition to these, the recipe offers these new options. They are33In addition to these, the recipe offers these new options. They are
34introduced here, and described more in depth below.34introduced here, and described more in depth below.
3535
36add-site-packages36include-site-packages
37 You can choose to have the site-packages of the underlying Python37 You can choose to have the site-packages of the underlying Python
38 available to your script or interpreter, in addition to the packages38 available to your script or interpreter, in addition to the packages
39 from your eggs. See the section on this option for motivations and39 from your eggs. See the section on this option for motivations and
@@ -47,7 +47,7 @@
47exec-sitecustomize47exec-sitecustomize
48 Normally the Python's real sitecustomize module is not processed.48 Normally the Python's real sitecustomize module is not processed.
49 If you want it to be processed, set this value to 'true'. This will49 If you want it to be processed, set this value to 'true'. This will
50 be honored irrespective of the setting for add-site-packages.50 be honored irrespective of the setting for include-site-packages.
5151
52script-initialization52script-initialization
53 The standard initialization code affects both an interpreter and scripts.53 The standard initialization code affects both an interpreter and scripts.
@@ -202,7 +202,7 @@
202possibilities. Don't be unaware of the dangers.202possibilities. Don't be unaware of the dangers.
203203
204To show off these features, we need to use buildout with a Python204To show off these features, we need to use buildout with a Python
205executable with some extra paths to show ``add-site-packages``; and one205executable with some extra paths to show ``include-site-packages``; and one
206guaranteed to have a sitecustomize module to show206guaranteed to have a sitecustomize module to show
207``exec-sitecustomize``. We'll make one using a test fixture called207``exec-sitecustomize``. We'll make one using a test fixture called
208``make_py``. The os.environ change below will go into the sitecustomize,208``make_py``. The os.environ change below will go into the sitecustomize,
@@ -215,7 +215,7 @@
215 >>> print site_packages_path215 >>> print site_packages_path
216 /executable_buildout/site-packages216 /executable_buildout/site-packages
217217
218Now let's take a look at add-site-packages.218Now let's take a look at include-site-packages.
219219
220 >>> write(sample_buildout, 'buildout.cfg',220 >>> write(sample_buildout, 'buildout.cfg',
221 ... """221 ... """
@@ -225,7 +225,7 @@
225 ...225 ...
226 ... [py]226 ... [py]
227 ... recipe = z3c.recipe.scripts:interpreter227 ... recipe = z3c.recipe.scripts:interpreter
228 ... add-site-packages = true228 ... include-site-packages = true
229 ... eggs = demo<0.3229 ... eggs = demo<0.3
230 ... find-links = %(server)s230 ... find-links = %(server)s
231 ... index = %(server)s/index231 ... index = %(server)s/index
232232
=== modified file 'z3c.recipe.scripts_/src/z3c/recipe/scripts/scripts.py'
--- z3c.recipe.scripts_/src/z3c/recipe/scripts/scripts.py 2010-02-24 23:22:13 +0000
+++ z3c.recipe.scripts_/src/z3c/recipe/scripts/scripts.py 2010-02-24 23:22:13 +0000
@@ -31,13 +31,13 @@
31 b_options['parts-directory'], self.name)31 b_options['parts-directory'], self.name)
3232
33 value = options.setdefault(33 value = options.setdefault(
34 'add-site-packages',34 'include-site-packages',
35 b_options.get('add-site-packages', 'false'))35 b_options.get('include-site-packages', 'false'))
36 if value not in ('true', 'false'):36 if value not in ('true', 'false'):
37 raise zc.buildout.UserError(37 raise zc.buildout.UserError(
38 "Invalid value for add-site-packages option: %s" %38 "Invalid value for include-site-packages option: %s" %
39 (value,))39 (value,))
40 self.add_site_packages = (value == 'true')40 self.include_site_packages = (value == 'true')
4141
42 value = options.setdefault(42 value = options.setdefault(
43 'exec-sitecustomize',43 'exec-sitecustomize',
@@ -69,7 +69,7 @@
69 interpreter=options['name'],69 interpreter=options['name'],
70 extra_paths=self.extra_paths,70 extra_paths=self.extra_paths,
71 initialization=options.get('initialization', ''),71 initialization=options.get('initialization', ''),
72 add_site_packages=self.add_site_packages,72 include_site_packages=self.include_site_packages,
73 exec_sitecustomize=self.exec_sitecustomize,73 exec_sitecustomize=self.exec_sitecustomize,
74 relative_paths=self._relative_paths,74 relative_paths=self._relative_paths,
75 ))75 ))
@@ -92,7 +92,7 @@
92 interpreter=options.get('interpreter'),92 interpreter=options.get('interpreter'),
93 extra_paths=self.extra_paths,93 extra_paths=self.extra_paths,
94 initialization=options.get('initialization', ''),94 initialization=options.get('initialization', ''),
95 add_site_packages=self.add_site_packages,95 include_site_packages=self.include_site_packages,
96 exec_sitecustomize=self.exec_sitecustomize,96 exec_sitecustomize=self.exec_sitecustomize,
97 relative_paths=self._relative_paths,97 relative_paths=self._relative_paths,
98 script_arguments=options.get('arguments', ''),98 script_arguments=options.get('arguments', ''),
9999
=== modified file 'z3c.recipe.scripts_/src/z3c/recipe/scripts/tests.py'
--- z3c.recipe.scripts_/src/z3c/recipe/scripts/tests.py 2010-02-24 23:22:13 +0000
+++ z3c.recipe.scripts_/src/z3c/recipe/scripts/tests.py 2010-02-24 23:22:13 +0000
@@ -25,7 +25,7 @@
25# all of the examples. The README tests ``extends``,25# all of the examples. The README tests ``extends``,
26# ``include-site-customization`` and ``name``. That leaves ``python``,26# ``include-site-customization`` and ``name``. That leaves ``python``,
27# ``extra-paths``, ``initialization``, ``relative-paths``, and27# ``extra-paths``, ``initialization``, ``relative-paths``, and
28# ``add-site-packages``.28# ``include-site-packages``.
2929
30def supports_python_option():30def supports_python_option():
31 """31 """

Subscribers

People subscribed via source and target branches

to all changes: