Commit 89cc72e5 authored by Gary Poster's avatar Gary Poster

set up PYTHONPATH for scripts too, so subprocesses are good to go by default.

parent 9ed408ec
...@@ -355,7 +355,9 @@ class Buildout(UserDict.DictMixin): ...@@ -355,7 +355,9 @@ class Buildout(UserDict.DictMixin):
if options.get('offline') == 'true': if options.get('offline') == 'true':
ws = zc.buildout.easy_install.working_set( ws = zc.buildout.easy_install.working_set(
distributions, options['executable'], distributions, options['executable'],
[options['develop-eggs-directory'], options['eggs-directory']] [options['develop-eggs-directory'],
options['eggs-directory']],
include_site_packages=False,
) )
else: else:
ws = zc.buildout.easy_install.install( ws = zc.buildout.easy_install.install(
...@@ -365,7 +367,8 @@ class Buildout(UserDict.DictMixin): ...@@ -365,7 +367,8 @@ class Buildout(UserDict.DictMixin):
executable=options['executable'], executable=options['executable'],
path=[options['develop-eggs-directory']], path=[options['develop-eggs-directory']],
newest=self.newest, newest=self.newest,
allow_hosts=self._allow_hosts allow_hosts=self._allow_hosts,
include_site_packages=False,
) )
# Now copy buildout and setuptools eggs, and record destination eggs: # Now copy buildout and setuptools eggs, and record destination eggs:
...@@ -1034,7 +1037,8 @@ def _install_and_load(spec, group, entry, buildout): ...@@ -1034,7 +1037,8 @@ def _install_and_load(spec, group, entry, buildout):
path=path, path=path,
working_set=pkg_resources.working_set, working_set=pkg_resources.working_set,
newest=buildout.newest, newest=buildout.newest,
allow_hosts=buildout._allow_hosts allow_hosts=buildout._allow_hosts,
include_site_packages=False,
) )
__doing__ = 'Loading %s recipe entry %s:%s.', group, spec, entry __doing__ = 'Loading %s recipe entry %s:%s.', group, spec, entry
......
...@@ -99,6 +99,7 @@ def _get_system_paths(executable): ...@@ -99,6 +99,7 @@ def _get_system_paths(executable):
"print repr([os.path.normpath(p) for p in sys.path if p])"]) "print repr([os.path.normpath(p) for p in sys.path if p])"])
# Windows needs some (as yet to be determined) part of the real env. # Windows needs some (as yet to be determined) part of the real env.
env = os.environ.copy() env = os.environ.copy()
env.pop('PYTHONPATH', None)
env.update(kwargs) env.update(kwargs)
_proc = subprocess.Popen( _proc = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
...@@ -337,9 +338,6 @@ class Installer: ...@@ -337,9 +338,6 @@ class Installer:
self._site_packages)) self._site_packages))
if self._include_site_packages: if self._include_site_packages:
path.extend(self._site_packages) path.extend(self._site_packages)
# else we could try to still include the buildout_and_setuptools_path
# if the elements are not in site_packages, but we're not bothering
# with this optimization for now, in the name of code simplicity.
if dest is not None and dest not in path: if dest is not None and dest not in path:
path.insert(0, dest) path.insert(0, dest)
self._path = path self._path = path
...@@ -1184,9 +1182,9 @@ def sitepackage_safe_scripts( ...@@ -1184,9 +1182,9 @@ def sitepackage_safe_scripts(
generated.append(_generate_site( generated.append(_generate_site(
site_py_dest, working_set, executable, extra_paths, site_py_dest, working_set, executable, extra_paths,
include_site_packages, relative_paths)) include_site_packages, relative_paths))
script_initialization = ( script_initialization = _script_initialization_template % dict(
'\nimport site # imports custom buildout-generated site.py\n%s' % ( site_py_dest=site_py_dest,
script_initialization,)) script_initialization=script_initialization)
if not script_initialization.endswith('\n'): if not script_initialization.endswith('\n'):
script_initialization += '\n' script_initialization += '\n'
generated.extend(_generate_scripts( generated.extend(_generate_scripts(
...@@ -1197,6 +1195,15 @@ def sitepackage_safe_scripts( ...@@ -1197,6 +1195,15 @@ def sitepackage_safe_scripts(
interpreter, dest, executable, site_py_dest, relative_paths)) interpreter, dest, executable, site_py_dest, relative_paths))
return generated return generated
_script_initialization_template = '''
import site # imports custom buildout-generated site.py
import os
path = %(site_py_dest)r
if os.environ.get('PYTHONPATH'):
path = os.pathsep.join([path, os.environ['PYTHONPATH']])
os.environ['PYTHONPATH'] = path
%(script_initialization)s'''
# Utilities for the script generation functions. # Utilities for the script generation functions.
# These are shared by both ``scripts`` and ``sitepackage_safe_scripts`` # These are shared by both ``scripts`` and ``sitepackage_safe_scripts``
......
...@@ -1499,6 +1499,11 @@ The demo script runs the entry point defined in the demo egg: ...@@ -1499,6 +1499,11 @@ The demo script runs the entry point defined in the demo egg:
<BLANKLINE> <BLANKLINE>
<BLANKLINE> <BLANKLINE>
import site # imports custom buildout-generated site.py import site # imports custom buildout-generated site.py
import os
path = '/interpreter/parts/interpreter'
if os.environ.get('PYTHONPATH'):
path = os.pathsep.join([path, os.environ['PYTHONPATH']])
os.environ['PYTHONPATH'] = path
<BLANKLINE> <BLANKLINE>
import eggrecipedemo import eggrecipedemo
<BLANKLINE> <BLANKLINE>
...@@ -1528,7 +1533,7 @@ Let's see ``script_arguments`` and ``script_initialization`` in action. ...@@ -1528,7 +1533,7 @@ Let's see ``script_arguments`` and ``script_initialization`` in action.
>>> generated = zc.buildout.easy_install.sitepackage_safe_scripts( >>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir, ... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
... reqs=['demo'], script_arguments='1, 2', ... reqs=['demo'], script_arguments='1, 2',
... script_initialization='import os\nos.chdir("foo")') ... script_initialization='import os\nos.chdir("foo")')
>>> cat(demo_path) # doctest: +NORMALIZE_WHITESPACE >>> cat(demo_path) # doctest: +NORMALIZE_WHITESPACE
#!/usr/local/bin/python2.4 -S #!/usr/local/bin/python2.4 -S
...@@ -1539,6 +1544,11 @@ Let's see ``script_arguments`` and ``script_initialization`` in action. ...@@ -1539,6 +1544,11 @@ Let's see ``script_arguments`` and ``script_initialization`` in action.
<BLANKLINE> <BLANKLINE>
import site # imports custom buildout-generated site.py import site # imports custom buildout-generated site.py
import os import os
path = '/interpreter/parts/interpreter'
if os.environ.get('PYTHONPATH'):
path = os.pathsep.join([path, os.environ['PYTHONPATH']])
os.environ['PYTHONPATH'] = path
import os
os.chdir("foo") os.chdir("foo")
<BLANKLINE> <BLANKLINE>
import eggrecipedemo import eggrecipedemo
......
...@@ -2254,8 +2254,50 @@ include-site-packages. ...@@ -2254,8 +2254,50 @@ include-site-packages.
""" """
def bootstrap_makes_buildout_that_works_with_system_python(): def subprocesses_have_same_environment_by_default():
"""
The scripts generated by sitepackage_safe_scripts set the PYTHONPATH so that,
if the environment is maintained (the default behavior), subprocesses get
the same Python packages.
First, we set up a script and an interpreter.
>>> 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/')
>>> test = (
... "import subprocess, sys; subprocess.call("
... "[sys.executable, '-c', "
... "'import eggrecipedemo; print eggrecipedemo.x'])")
>>> generated = zc.buildout.easy_install.sitepackage_safe_scripts(
... interpreter_bin_dir, ws, sys.executable, interpreter_parts_dir,
... reqs=['demo'], interpreter='py',
... script_initialization=test + '; sys.exit(0)')
This works for the script.
>>> print system(join(interpreter_bin_dir, 'demo'))
3
<BLANKLINE>
This also works for the generated interpreter.
>>> print call_py(join(interpreter_bin_dir, 'py'), test)
3
<BLANKLINE>
""" """
def bootstrap_makes_buildout_that_works_with_system_python():
r"""
In order to work smoothly with a system Python, bootstrapping creates In order to work smoothly with a system Python, bootstrapping creates
the buildout script with the buildout script with
zc.buildout.easy_install.sitepackage_safe_scripts. If it did not, a zc.buildout.easy_install.sitepackage_safe_scripts. If it did not, a
...@@ -2274,15 +2316,11 @@ First let's write a dummy recipe. ...@@ -2274,15 +2316,11 @@ First let's write a dummy recipe.
>>> write(sample_buildout, 'recipes', 'dummy.py', >>> write(sample_buildout, 'recipes', 'dummy.py',
... ''' ... '''
... import logging, os, zc.buildout ... import logging, os, zc.buildout
...
... class Dummy: ... class Dummy:
...
... def __init__(self, buildout, name, options): ... def __init__(self, buildout, name, options):
... pass ... pass
...
... def install(self): ... def install(self):
... return () ... return ()
...
... def update(self): ... def update(self):
... pass ... pass
... ''') ... ''')
...@@ -2340,6 +2378,67 @@ Now, it is handled smoothly. ...@@ -2340,6 +2378,67 @@ Now, it is handled smoothly.
Installing dummy. Installing dummy.
<BLANKLINE> <BLANKLINE>
Here's the same story with a namespace package, which has some additional
complications behind the scenes. First, a recipe, in the "tellmy" namespace.
>>> mkdir(sample_buildout, 'ns')
>>> mkdir(sample_buildout, 'ns', 'tellmy')
>>> write(sample_buildout, 'ns', 'tellmy', '__init__.py',
... "__import__('pkg_resources').declare_namespace(__name__)\n")
>>> mkdir(sample_buildout, 'ns', 'tellmy', 'recipes')
>>> write(sample_buildout, 'ns', 'tellmy', 'recipes', '__init__.py', ' ')
>>> write(sample_buildout, 'ns', 'tellmy', 'recipes', 'dummy.py',
... '''
... import logging, os, zc.buildout
... class Dummy:
... def __init__(self, buildout, name, options):
... pass
... def install(self):
... return ()
... def update(self):
... pass
... ''')
>>> write(sample_buildout, 'ns', 'setup.py',
... '''
... from setuptools import setup
... setup(
... name="tellmy.recipes",
... packages=['tellmy', 'tellmy.recipes'],
... install_requires=['setuptools'],
... namespace_packages=['tellmy'],
... entry_points = {'zc.buildout':
... ['dummy = tellmy.recipes.dummy:Dummy']},
... )
... ''')
Now, a buildout that uses it.
>>> create_sample_namespace_eggs(sample_eggs, site_packages_path)
>>> rmdir('develop-eggs')
>>> from zc.buildout.testing import make_buildout
>>> make_buildout(executable=py_path)
>>> write(sample_buildout, 'buildout.cfg',
... '''
... [buildout]
... develop = ns
... recipes
... parts = dummy
... find-links = %(link_server)s
... executable = %(py_path)s
...
... [dummy]
... recipe = tellmy.recipes:dummy
... ''' % globals())
Now we actually run the buildout.
>>> print system(buildout)
Develop: '/sample-buildout/ns'
Develop: '/sample-buildout/recipes'
Uninstalling dummy.
Installing dummy.
<BLANKLINE>
""" """
if sys.version_info > (2, 4): if sys.version_info > (2, 4):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment