[Checkins] SVN: zc.recipe.testrunner/trunk/ update to zc.buildout 1.5.0 support. Development works with system Python.
Gary Poster
gary.poster at canonical.com
Fri Aug 27 22:44:24 EDT 2010
Log message for revision 115978:
update to zc.buildout 1.5.0 support. Development works with system Python.
Changed:
U zc.recipe.testrunner/trunk/CHANGES.txt
U zc.recipe.testrunner/trunk/bootstrap.py
U zc.recipe.testrunner/trunk/setup.py
U zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/README.txt
U zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/__init__.py
U zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/tests.py
-=-
Modified: zc.recipe.testrunner/trunk/CHANGES.txt
===================================================================
--- zc.recipe.testrunner/trunk/CHANGES.txt 2010-08-28 02:18:57 UTC (rev 115977)
+++ zc.recipe.testrunner/trunk/CHANGES.txt 2010-08-28 02:44:24 UTC (rev 115978)
@@ -5,6 +5,10 @@
1.4.0 (unreleased)
==================
+- Update to using zc.buildout 1.5.0 script generation. This adds the
+ following options: include-site-packages, allowed-eggs-from-site-packages,
+ extends, and exec-sitecustomize.
+
- Merge fixes from 1.2.1 (svn://svn.zope.org/repos/main/zc.recipe.testrunner/tags/1.2.1)
Excluding nailing zope.testing version. That fixes a bunch of windows issues
@@ -13,7 +17,7 @@
- Updated tests to run with the last versions of all modules.
-- Removed the usage of the deprecated zope.testing.doctest, therby also
+- Removed the usage of the deprecated zope.testing.doctest, thereby also
dropping Python 2.3 support.
- Started using zope.testrunner instead of zope.testing.testrunner.
Modified: zc.recipe.testrunner/trunk/bootstrap.py
===================================================================
--- zc.recipe.testrunner/trunk/bootstrap.py 2010-08-28 02:18:57 UTC (rev 115977)
+++ zc.recipe.testrunner/trunk/bootstrap.py 2010-08-28 02:44:24 UTC (rev 115978)
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2006 Zope Corporation and Contributors.
+# Copyright (c) 2006 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -16,37 +16,243 @@
Simply run this script in a directory containing a buildout.cfg.
The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file.
-
-$Id$
"""
-import os, shutil, sys, tempfile, urllib2
+import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
+from optparse import OptionParser
-tmpeggs = tempfile.mkdtemp()
+if sys.platform == 'win32':
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ quote = str
-ez = {}
-exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
- ).read() in ez
-ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
+stdout, stderr = subprocess.Popen(
+ [sys.executable, '-Sc',
+ 'try:\n'
+ ' import ConfigParser\n'
+ 'except ImportError:\n'
+ ' print 1\n'
+ 'else:\n'
+ ' print 0\n'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+has_broken_dash_S = bool(int(stdout.strip()))
-import pkg_resources
+# In order to be more robust in the face of system Pythons, we want to
+# run without site-packages loaded. This is somewhat tricky, in
+# particular because Python 2.6's distutils imports site, so starting
+# with the -S flag is not sufficient. However, we'll start with that:
+if not has_broken_dash_S and 'site' in sys.modules:
+ # We will restart with python -S.
+ args = sys.argv[:]
+ args[0:0] = [sys.executable, '-S']
+ args = map(quote, args)
+ os.execv(sys.executable, args)
+# Now we are running with -S. We'll get the clean sys.path, import site
+# because distutils will do it later, and then reset the path and clean
+# out any namespace packages from site-packages that might have been
+# loaded by .pth files.
+clean_path = sys.path[:]
+import site
+sys.path[:] = clean_path
+for k, v in sys.modules.items():
+ if (hasattr(v, '__path__') and
+ len(v.__path__)==1 and
+ not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
+ # This is a namespace package. Remove it.
+ sys.modules.pop(k)
-cmd = 'from setuptools.command.easy_install import main; main()'
-if sys.platform == 'win32':
- cmd = '"%s"' % cmd # work around spawn lamosity on windows
+is_jython = sys.platform.startswith('java')
+setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
+distribute_source = 'http://python-distribute.org/distribute_setup.py'
+
+# parsing arguments
+def normalize_to_url(option, opt_str, value, parser):
+ if value:
+ if '://' not in value: # It doesn't smell like a URL.
+ value = 'file://%s' % (
+ urllib.pathname2url(
+ os.path.abspath(os.path.expanduser(value))),)
+ if opt_str == '--download-base' and not value.endswith('/'):
+ # Download base needs a trailing slash to make the world happy.
+ value += '/'
+ else:
+ value = None
+ name = opt_str[2:].replace('-', '_')
+ setattr(parser.values, name, value)
+
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
+
+Bootstraps a buildout-based project.
+
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", dest="version",
+ help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+ action="store_true", dest="use_distribute", default=False,
+ help="Use Distribute rather than Setuptools.")
+parser.add_option("--setup-source", action="callback", dest="setup_source",
+ callback=normalize_to_url, nargs=1, type="string",
+ help=("Specify a URL or file location for the setup file. "
+ "If you use Setuptools, this will default to " +
+ setuptools_source + "; if you use Distribute, this "
+ "will default to " + distribute_source +"."))
+parser.add_option("--download-base", action="callback", dest="download_base",
+ callback=normalize_to_url, nargs=1, type="string",
+ help=("Specify a URL or directory for downloading "
+ "zc.buildout and either Setuptools or Distribute. "
+ "Defaults to PyPI."))
+parser.add_option("--eggs",
+ help=("Specify a directory for storing eggs. Defaults to "
+ "a temporary directory that is deleted when the "
+ "bootstrap script completes."))
+parser.add_option("-t", "--accept-buildout-test-releases",
+ dest='accept_buildout_test_releases',
+ action="store_true", default=False,
+ help=("Normally, if you do not specify a --version, the "
+ "bootstrap script and buildout gets the newest "
+ "*final* versions of zc.buildout and its recipes and "
+ "extensions for you. If you use this flag, "
+ "bootstrap and buildout will get the newest releases "
+ "even if they are alphas or betas."))
+parser.add_option("-c", None, action="store", dest="config_file",
+ help=("Specify the path to the buildout configuration "
+ "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout's main function
+if options.config_file is not None:
+ args += ['-c', options.config_file]
+
+if options.eggs:
+ eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
+else:
+ eggs_dir = tempfile.mkdtemp()
+
+if options.setup_source is None:
+ if options.use_distribute:
+ options.setup_source = distribute_source
+ else:
+ options.setup_source = setuptools_source
+
+if options.accept_buildout_test_releases:
+ args.append('buildout:accept-buildout-test-releases=true')
+args.append('bootstrap')
+
+try:
+ import pkg_resources
+ import setuptools # A flag. Sometimes pkg_resources is installed alone.
+ if not hasattr(pkg_resources, '_distribute'):
+ raise ImportError
+except ImportError:
+ ez_code = urllib2.urlopen(
+ options.setup_source).read().replace('\r\n', '\n')
+ ez = {}
+ exec ez_code in ez
+ setup_args = dict(to_dir=eggs_dir, download_delay=0)
+ if options.download_base:
+ setup_args['download_base'] = options.download_base
+ if options.use_distribute:
+ setup_args['no_fake'] = True
+ ez['use_setuptools'](**setup_args)
+ reload(sys.modules['pkg_resources'])
+ import pkg_resources
+ # This does not (always?) update the default working set. We will
+ # do it.
+ for path in sys.path:
+ if path not in pkg_resources.working_set.entries:
+ pkg_resources.working_set.add_entry(path)
+
+cmd = [quote(sys.executable),
+ '-c',
+ quote('from setuptools.command.easy_install import main; main()'),
+ '-mqNxd',
+ quote(eggs_dir)]
+
+if not has_broken_dash_S:
+ cmd.insert(1, '-S')
+
+find_links = options.download_base
+if not find_links:
+ find_links = os.environ.get('bootstrap-testing-find-links')
+if find_links:
+ cmd.extend(['-f', quote(find_links)])
+
+if options.use_distribute:
+ setup_requirement = 'distribute'
+else:
+ setup_requirement = 'setuptools'
ws = pkg_resources.working_set
-assert os.spawnle(
- os.P_WAIT, sys.executable, sys.executable,
- '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
- dict(os.environ,
- PYTHONPATH=
- ws.find(pkg_resources.Requirement.parse('setuptools')).location
- ),
- ) == 0
+setup_requirement_path = ws.find(
+ pkg_resources.Requirement.parse(setup_requirement)).location
+env = dict(
+ os.environ,
+ PYTHONPATH=setup_requirement_path)
-ws.add_entry(tmpeggs)
-ws.require('zc.buildout')
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+ # Figure out the most recent final version of zc.buildout.
+ import setuptools.package_index
+ _final_parts = '*final-', '*final'
+ def _final_version(parsed_version):
+ for part in parsed_version:
+ if (part[:1] == '*') and (part not in _final_parts):
+ return False
+ return True
+ index = setuptools.package_index.PackageIndex(
+ search_path=[setup_requirement_path])
+ if find_links:
+ index.add_find_links((find_links,))
+ req = pkg_resources.Requirement.parse(requirement)
+ if index.obtain(req) is not None:
+ best = []
+ bestv = None
+ for dist in index[req.project_name]:
+ distv = dist.parsed_version
+ if _final_version(distv):
+ if bestv is None or distv > bestv:
+ best = [dist]
+ bestv = distv
+ elif distv == bestv:
+ best.append(dist)
+ if best:
+ best.sort()
+ version = best[-1].version
+if version:
+ requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+if is_jython:
+ import subprocess
+ exitcode = subprocess.Popen(cmd, env=env).wait()
+else: # Windows prefers this, apparently; otherwise we would prefer subprocess
+ exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
+if exitcode != 0:
+ sys.stdout.flush()
+ sys.stderr.flush()
+ print ("An error occurred when trying to install zc.buildout. "
+ "Look above this message for any errors that "
+ "were output by easy_install.")
+ sys.exit(exitcode)
+
+ws.add_entry(eggs_dir)
+ws.require(requirement)
import zc.buildout.buildout
-zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
-shutil.rmtree(tmpeggs)
+zc.buildout.buildout.main(args)
+if not options.eggs: # clean up temporary egg directory
+ shutil.rmtree(eggs_dir)
Modified: zc.recipe.testrunner/trunk/setup.py
===================================================================
--- zc.recipe.testrunner/trunk/setup.py 2010-08-28 02:18:57 UTC (rev 115977)
+++ zc.recipe.testrunner/trunk/setup.py 2010-08-28 02:44:24 UTC (rev 115978)
@@ -32,10 +32,10 @@
extras_require = {
'tests': ['zope.testing'],
},
- install_requires = ['zc.buildout >=1.2.0',
+ install_requires = ['zc.buildout >=1.5.0',
'zope.testrunner',
'setuptools',
- 'zc.recipe.egg >=1.2.0',
+ 'z3c.recipe.scripts >=1.0.0',
],
tests_require = ['zope.testing'],
test_suite = name+'.tests.test_suite',
Modified: zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/README.txt
===================================================================
--- zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/README.txt 2010-08-28 02:18:57 UTC (rev 115977)
+++ zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/README.txt 2010-08-28 02:44:24 UTC (rev 115978)
@@ -40,6 +40,53 @@
relative-paths
Use egg, test, and working-directory paths relative to the test script.
+include-site-packages
+ You can choose to have the site-packages of the underlying Python
+ available to your script or interpreter, in addition to the packages
+ from your eggs. See `the z3c.recipe.scripts documentation`_ for
+ motivations and warnings.
+
+allowed-eggs-from-site-packages
+ Sometimes you need or want to control what eggs from site-packages are
+ used. The allowed-eggs-from-site-packages option allows you to specify a
+ whitelist of project names that may be included from site-packages. You
+ can use globs to specify the value. It defaults to a single value of '*',
+ indicating that any package may come from site-packages.
+
+ Here's a usage example::
+
+ [buildout]
+ ...
+
+ allowed-eggs-from-site-packages =
+ demo
+ bigdemo
+ zope.*
+
+ This option interacts with the ``include-site-packages`` option in the
+ following ways.
+
+ If ``include-site-packages`` is true, then
+ ``allowed-eggs-from-site-packages`` filters what eggs from site-packages
+ may be chosen. Therefore, if ``allowed-eggs-from-site-packages`` is an
+ empty list, then no eggs from site-packages are chosen, but site-packages
+ will still be included at the end of path lists.
+
+ If ``include-site-packages`` is false, the value of
+ ``allowed-eggs-from-site-packages`` is irrelevant.
+
+extends
+ You can extend another section using this value. It is intended to help
+ you avoid repeating yourself.
+
+exec-sitecustomize
+ Normally the Python's real sitecustomize module is not processed.
+ If you want it to be processed, set this value to 'true'. This will
+ be honored irrespective of the setting for include-site-packages.
+
+.. _`the z3c.recipe.scripts documentation`:
+ http://pypi.python.org/pypi/z3c.recipe.scripts#including-site-packages-and-sitecustomize
+
(Note that, at this time, due to limitations in the Zope test runner, the
distributions cannot be zip files. TODO: Fix the test runner!)
@@ -155,20 +202,27 @@
- buildout
- test
-We also get a part directory for the tests to run in:
+We also get a "testdemo" parts directory:
>>> ls(sample_buildout, 'parts')
+ d buildout
d testdemo
+The testdemo directory has a "working-directory," in which tests are run.
+(The site-packages directory is support for the test script.)
-And updating leaves its contents intact:
+ >>> ls(sample_buildout, 'parts', 'testdemo')
+ d site-packages
+ d working-directory
+Updating leaves its contents intact:
+
>>> _ = system(os.path.join(sample_buildout, 'bin', 'test') +
... ' -q --coverage=coverage')
- >>> ls(sample_buildout, 'parts', 'testdemo')
+ >>> ls(sample_buildout, 'parts', 'testdemo', 'working-directory')
d coverage
>>> print system(os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
- >>> ls(sample_buildout, 'parts', 'testdemo')
+ >>> ls(sample_buildout, 'parts', 'testdemo', 'working-directory')
d coverage
We can run the test script to run our demo test:
@@ -235,30 +289,22 @@
>>> print system(os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
- >>> cat(sample_buildout, 'bin', 'testdemo')
- #!/usr/local/bin/python2.4
+ >>> cat(sample_buildout, 'parts', 'testdemo', 'site-packages', 'site.py')
+ ... # doctest: +ELLIPSIS
+ "...
+ def addsitepackages(known_paths):
+ """Add site packages, as determined by zc.buildout.
<BLANKLINE>
- import sys
- sys.path[0:0] = [
- '/sample-buildout/demo',
- '/sample-buildout/eggs/zope.testrunner-4.0-py2.3.egg',
- '/sample-buildout/eggs/zope.interface-3.4.1-py2.4.egg',
- '/sample-buildout/eggs/zope.exceptions-3.5.2-py2.4.egg',
- '/sample-buildout/eggs/setuptools-0.6-py1.3.egg',
- '/usr/local/zope/lib/python',
- ]
- <BLANKLINE>
- import os
- sys.argv[0] = os.path.abspath(sys.argv[0])
- os.chdir('/sample-buildout/parts/testdemo')
- <BLANKLINE>
- <BLANKLINE>
- import zope.testrunner
- <BLANKLINE>
- if __name__ == '__main__':
- zope.testrunner.run([
- '--test-path', '/sample-buildout/demo',
- ])
+ See original_addsitepackages, below, for the original version."""
+ buildout_paths = [
+ '/sample-buildout/demo',
+ '/sample-buildout/eggs/zope.testrunner-4.0-py2.3.egg',
+ '/sample-buildout/eggs/zope.interface-3.4.1-py2.4.egg',
+ '/sample-buildout/eggs/zope.exceptions-3.5.2-py2.4.egg',
+ '/sample-buildout/eggs/setuptools-0.6-py1.3.egg',
+ '/usr/local/zope/lib/python'
+ ]
+ ...
We can use the working-directory option to specify a working
directory:
@@ -280,23 +326,24 @@
>>> print system(os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
>>> cat(sample_buildout, 'bin', 'testdemo')
- #!/usr/local/bin/python2.4
+ #!/usr/local/bin/python2.4 -S
<BLANKLINE>
import sys
sys.path[0:0] = [
- '/sample-buildout/demo',
- '/sample-buildout/eggs/zope.testrunner-4.0-py2.3.egg',
- '/sample-buildout/eggs/zope.interface-3.4.1-py2.4.egg',
- '/sample-buildout/eggs/zope.exceptions-3.5.2-py2.4.egg',
- '/sample-buildout/eggs/setuptools-0.6-py1.3.egg',
- '/usr/local/zope/lib/python',
- ]
+ '/sample-buildout/parts/testdemo/site-packages',
+ ]
<BLANKLINE>
+ <BLANKLINE>
import os
+ path = sys.path[0]
+ if os.environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, os.environ['PYTHONPATH']])
+ os.environ['PYTHONPATH'] = path
+ import site # imports custom buildout-generated site.py
+ import os
sys.argv[0] = os.path.abspath(sys.argv[0])
os.chdir('/foo/bar')
<BLANKLINE>
- <BLANKLINE>
import zope.testrunner
<BLANKLINE>
if __name__ == '__main__':
@@ -304,11 +351,13 @@
'--test-path', '/sample-buildout/demo',
])
-Now that out tests use a specified working directory, their designated
+Now that our tests use a specified working directory, their designated
part directory is gone:
- >>> ls(sample_buildout, 'parts')
+ >>> ls(sample_buildout, 'parts', 'testdemo')
+ d site-packages
+
If we need to specify default options, we can use the defaults
option. For example, Zope 3 applications typically define test suites
in modules named ftests or tests. The default test runner behaviour
@@ -336,23 +385,24 @@
>>> print system(os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
>>> cat(sample_buildout, 'bin', 'testdemo')
- #!/usr/local/bin/python2.4
+ #!/usr/local/bin/python2.4 -S
<BLANKLINE>
import sys
sys.path[0:0] = [
- '/sample-buildout/demo',
- '/sample-buildout/eggs/zope.testrunner-4.0-py2.3.egg',
- '/sample-buildout/eggs/zope.interface-3.4.1-py2.4.egg',
- '/sample-buildout/eggs/zope.exceptions-3.5.2-py2.4.egg',
- '/sample-buildout/eggs/setuptools-0.6-py1.3.egg',
- '/usr/local/zope/lib/python',
- ]
+ '/sample-buildout/parts/testdemo/site-packages',
+ ]
<BLANKLINE>
+ <BLANKLINE>
import os
+ path = sys.path[0]
+ if os.environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, os.environ['PYTHONPATH']])
+ os.environ['PYTHONPATH'] = path
+ import site # imports custom buildout-generated site.py
+ import os
sys.argv[0] = os.path.abspath(sys.argv[0])
- os.chdir('/sample-buildout/parts/testdemo')
+ os.chdir('/sample-buildout/parts/testdemo/working-directory')
<BLANKLINE>
- <BLANKLINE>
import zope.testrunner
<BLANKLINE>
if __name__ == '__main__':
@@ -362,6 +412,7 @@
'--test-path', '/sample-buildout/demo',
])
+
Some things to note from this example:
- Parentheses are placed around the given expression.
@@ -434,23 +485,25 @@
>>> print system(os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
>>> cat(sample_buildout, 'bin', 'testdemo')
- #!/usr/local/bin/python2.4
+ #!/usr/local/bin/python2.4 -S
<BLANKLINE>
import sys
sys.path[0:0] = [
- '/sample-buildout/demo',
- '/sample-buildout/eggs/zope.testrunner-4.0-py2.3.egg',
- '/sample-buildout/eggs/zope.interface-3.4.1-py2.4.egg',
- '/sample-buildout/eggs/zope.exceptions-3.5.2-py2.4.egg',
- '/sample-buildout/eggs/setuptools-0.6-py1.3.egg',
- ]
+ '/sample-buildout/parts/testdemo/site-packages',
+ ]
<BLANKLINE>
+ <BLANKLINE>
import os
+ path = sys.path[0]
+ if os.environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, os.environ['PYTHONPATH']])
+ os.environ['PYTHONPATH'] = path
+ import site # imports custom buildout-generated site.py
+ import os
sys.argv[0] = os.path.abspath(sys.argv[0])
- os.chdir('/sample-buildout/parts/testdemo')
+ os.chdir('/sample-buildout/parts/testdemo/working-directory')
os.environ['zc.recipe.testrunner'] = '42'
<BLANKLINE>
- <BLANKLINE>
import zope.testrunner
<BLANKLINE>
if __name__ == '__main__':
@@ -491,21 +544,23 @@
>>> print system(os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
>>> cat(sample_buildout, 'bin', 'testdemo')
- #!/usr/local/bin/python2.4
+ #!/usr/local/bin/python2.4 -S
<BLANKLINE>
import sys
sys.path[0:0] = [
- '/sample-buildout/demo',
- '/sample-buildout/eggs/zope.testrunner-4.0-py2.3.egg',
- '/sample-buildout/eggs/zope.interface-3.4.1-py2.4.egg',
- '/sample-buildout/eggs/zope.exceptions-3.5.2-py2.4.egg',
- '/sample-buildout/eggs/setuptools-0.6-py1.3.egg',
- '/usr/local/zope/lib/python',
- ]
+ '/sample-buildout/parts/testdemo/site-packages',
+ ]
<BLANKLINE>
+ <BLANKLINE>
import os
+ path = sys.path[0]
+ if os.environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, os.environ['PYTHONPATH']])
+ os.environ['PYTHONPATH'] = path
+ import site # imports custom buildout-generated site.py
+ import os
sys.argv[0] = os.path.abspath(sys.argv[0])
- os.chdir('/sample-buildout/parts/testdemo')
+ os.chdir('/sample-buildout/parts/testdemo/working-directory')
print 'Hello all you egg-laying pythons!'
<BLANKLINE>
import zope.testrunner
@@ -540,21 +595,23 @@
>>> print system(os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
>>> cat(sample_buildout, 'bin', 'testdemo')
- #!/usr/local/bin/python2.4
+ #!/usr/local/bin/python2.4 -S
<BLANKLINE>
import sys
sys.path[0:0] = [
- '/sample-buildout/demo',
- '/sample-buildout/eggs/zope.testrunner-4.0-py2.3.egg',
- '/sample-buildout/eggs/zope.interface-3.4.1-py2.4.egg',
- '/sample-buildout/eggs/zope.exceptions-3.5.2-py2.4.egg',
- '/sample-buildout/eggs/setuptools-0.6-py1.3.egg',
- '/usr/local/zope/lib/python',
- ]
+ '/sample-buildout/parts/testdemo/site-packages',
+ ]
<BLANKLINE>
+ <BLANKLINE>
import os
+ path = sys.path[0]
+ if os.environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, os.environ['PYTHONPATH']])
+ os.environ['PYTHONPATH'] = path
+ import site # imports custom buildout-generated site.py
+ import os
sys.argv[0] = os.path.abspath(sys.argv[0])
- os.chdir('/sample-buildout/parts/testdemo')
+ os.chdir('/sample-buildout/parts/testdemo/working-directory')
print 'Hello all you egg-laying pythons!'
print 'I thought pythons were live bearers?'
<BLANKLINE>
@@ -588,7 +645,7 @@
>>> print system(os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
>>> cat(sample_buildout, 'bin', 'testdemo')
- #!/usr/local/bin/python2.4
+ #!/usr/local/bin/python2.4 -S
<BLANKLINE>
import os
<BLANKLINE>
@@ -598,20 +655,20 @@
<BLANKLINE>
import sys
sys.path[0:0] = [
- join(base, 'demo'),
- join(base, 'eggs/zope.testrunner-4.0.0-py2.4.egg'),
- join(base, 'eggs/zope.interface-3.5.1-py2.4-linux-i686.egg'),
- join(base, 'eggs/zope.exceptions-3.5.2-linux-i686.egg'),
- join(base, 'eggs/setuptools-0.6c9-py2.4.egg'),
- '/usr/local/zope/lib/python',
- join(base, 'sources'),
- ]
+ join(base, 'parts/testdemo/site-packages'),
+ ]
<BLANKLINE>
+ <BLANKLINE>
import os
+ path = sys.path[0]
+ if os.environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, os.environ['PYTHONPATH']])
+ os.environ['PYTHONPATH'] = path
+ import site # imports custom buildout-generated site.py
+ import os
sys.argv[0] = os.path.abspath(sys.argv[0])
- os.chdir(join(base, 'parts/testdemo'))
+ os.chdir(join(base, 'parts/testdemo/working-directory'))
<BLANKLINE>
- <BLANKLINE>
import zope.testrunner
<BLANKLINE>
if __name__ == '__main__':
@@ -619,6 +676,29 @@
'--test-path', join(base, 'demo'),
])
+ >>> cat(sample_buildout, 'parts', 'testdemo', 'site-packages', 'site.py')
+ ... # 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)
+ base = os.path.dirname(base)
+ buildout_paths = [
+ join(base, 'demo'),
+ join(base, 'eggs/zope.testrunner-4.0.0-py2.4.egg'),
+ join(base, 'eggs/zope.interface-3.5.1-py2.4-linux-i686.egg'),
+ join(base, 'eggs/zope.exceptions-3.5.2-linux-i686.egg'),
+ join(base, 'eggs/setuptools-0.6c9-py2.4.egg'),
+ '/usr/local/zope/lib/python',
+ join(base, 'sources')
+ ]
+ ...
+
The relative-paths option can be specified at the buildout level:
>>> write(sample_buildout, 'buildout.cfg',
@@ -639,7 +719,7 @@
>>> print system(os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
>>> cat(sample_buildout, 'bin', 'testdemo')
- #!/usr/local/bin/python2.4
+ #!/usr/local/bin/python2.4 -S
<BLANKLINE>
import os
<BLANKLINE>
@@ -649,20 +729,20 @@
<BLANKLINE>
import sys
sys.path[0:0] = [
- join(base, 'demo'),
- join(base, 'eggs/zope.testrunner-4.0.0-py2.4.egg'),
- join(base, 'eggs/zope.interface-3.5.1-py2.4-linux-i686.egg'),
- join(base, 'eggs/zope.exceptions-3.5.2-linux-i686.egg'),
- join(base, 'eggs/setuptools-0.6c9-py2.4.egg'),
- '/usr/local/zope/lib/python',
- join(base, 'sources'),
- ]
+ join(base, 'parts/testdemo/site-packages'),
+ ]
<BLANKLINE>
+ <BLANKLINE>
import os
+ path = sys.path[0]
+ if os.environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, os.environ['PYTHONPATH']])
+ os.environ['PYTHONPATH'] = path
+ import site # imports custom buildout-generated site.py
+ import os
sys.argv[0] = os.path.abspath(sys.argv[0])
- os.chdir(join(base, 'parts/testdemo'))
+ os.chdir(join(base, 'parts/testdemo/working-directory'))
<BLANKLINE>
- <BLANKLINE>
import zope.testrunner
<BLANKLINE>
if __name__ == '__main__':
@@ -670,3 +750,368 @@
'--test-path', join(base, 'demo'),
])
+-------------------------
+Support for system Python
+-------------------------
+
+zc.recipe.testrunner 1.4.0 added support for zc.buildout 1.5's system Python
+support.
+
+By default, this means that, if the buildout is set up as described in the
+`pertinent section of the zc.buildout documentation`_ then the scripts
+generated by this recipe will be safe to use with a system Python.
+
+You can also use the same options as provided by z3c.recipe.scripts (and
+the functionality is delegated to code from this package). That package
+is well-tested, so this merely quickly demonstrates usage.
+
+include-site-packages
+---------------------
+
+Use this to include site-packages from the Python you are using.
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... develop = demo
+ ... parts = testdemo
+ ... offline = true
+ ...
+ ... [testdemo]
+ ... recipe = zc.recipe.testrunner
+ ... eggs = demo
+ ... include-site-packages = true
+ ... """)
+
+.. ReST comment: Hide the rest of the test from PyPI readers.
+
+ >>> ignore = system(
+ ... os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
+
+ >>> cat(sample_buildout, 'parts', 'testdemo', 'site-packages', 'site.py')
+ ... # doctest: +ELLIPSIS
+ "...
+ def addsitepackages(known_paths):
+ """Add site packages, as determined by zc.buildout.
+ <BLANKLINE>
+ See original_addsitepackages, below, for the original version."""
+ setuptools_path = '...'
+ sys.path.append(setuptools_path)
+ known_paths.add(os.path.normcase(setuptools_path))
+ import pkg_resources
+ buildout_paths = [
+ '/sample-buildout/demo',
+ '/sample-buildout/eggs/zope.testrunner-4.0-py2.3.egg',
+ '/sample-buildout/eggs/zope.exceptions-3.4.1-py2.4.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
+ ...
+
+Note that a setting in the buildout section will also be honored, if it is
+not overridden locally.
+
+.. ReST comment: Hide the test from PyPI readers.
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... develop = demo
+ ... parts = testdemo
+ ... offline = true
+ ... include-site-packages = true
+ ...
+ ... [testdemo]
+ ... recipe = zc.recipe.testrunner
+ ... eggs = demo
+ ... """)
+
+ >>> ignore = system(
+ ... os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
+
+ >>> cat(sample_buildout, 'parts', 'testdemo', 'site-packages', 'site.py')
+ ... # doctest: +ELLIPSIS
+ "...
+ def addsitepackages(known_paths):
+ """Add site packages, as determined by zc.buildout.
+ <BLANKLINE>
+ See original_addsitepackages, below, for the original version."""
+ setuptools_path = '...'
+ sys.path.append(setuptools_path)
+ known_paths.add(os.path.normcase(setuptools_path))
+ import pkg_resources
+ buildout_paths = [
+ '/sample-buildout/demo',
+ '/sample-buildout/eggs/zope.testrunner-4.0-py2.3.egg',
+ '/sample-buildout/eggs/zope.exceptions-3.4.1-py2.4.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
+ ...
+
+allowed-eggs-from-site-packages
+-------------------------------
+
+allowed-eggs-from-site-packages is described at the start of this document.
+It is a whitespace-delineated list of eggs that may be obtained from the
+filesystem. It may use wildcards, and it defaults to "*", accepting all
+eggs.
+
+Here's a demonstration of how you would use
+allowed-eggs-from-sitepackages to allow no eggs to come from the
+filesystem, but still let you import other packages (like PIL) from the
+filesystem. (Note that the eggs-directory and the executable are only
+part of making this documentation testable, and not necessary to use
+this option.)
+
+Imagine that the system Python has demo installed. If
+allowed-eggs-from-site-packages were its default value of '*', an
+installation would succeed, because it would be found in site-packages.
+However, this example would fail, because the site-packages version
+would not be allowed.
+
+.. ReST comment: unimportant for PyPI (comment ends at next "..")
+
+ >>> py_path, site_packages_path = make_py(initialization='''\
+ ... import os
+ ... os.environ['zc.buildout'] = 'foo bar baz shazam'
+ ... ''')
+ >>> from zc.buildout.tests import create_sample_sys_install
+ >>> create_sample_sys_install(site_packages_path)
+ >>> new_buildout = tmpdir('new_buildout')
+ >>> cd(new_buildout)
+ >>> mkdir(new_buildout, 'altdemo')
+ >>> mkdir(new_buildout, 'altdemo', 'demo')
+ >>> write(new_buildout, 'altdemo', 'demo', '__init__.py', '')
+ >>> write(new_buildout, 'altdemo', 'setup.py',
+ ... """
+ ... from setuptools import setup
+ ...
+ ... setup(name = "altdemo")
+ ... """)
+ >>> write(new_buildout, 'altdemo', 'README.txt', '')
+ >>> from zc.buildout.testing import install_develop, make_buildout
+ >>> make_buildout()
+ >>> install_develop(
+ ... 'zc.recipe.testrunner', os.path.join(new_buildout, 'develop-eggs'))
+ >>> install_develop(
+ ... 'zope.testrunner', os.path.join(new_buildout, 'develop-eggs'))
+ >>> install_develop(
+ ... 'zope.interface', os.path.join(new_buildout, 'develop-eggs'))
+ >>> install_develop(
+ ... 'zope.exceptions', os.path.join(new_buildout, 'develop-eggs'))
+ >>> install_develop(
+ ... 'zc.recipe.egg', os.path.join(new_buildout, 'develop-eggs'))
+ >>> install_develop(
+ ... 'z3c.recipe.scripts', os.path.join(new_buildout, 'develop-eggs'))
+
+..
+
+ >>> write(new_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... develop = altdemo
+ ... parts = testdemo
+ ... eggs-directory = tmpeggs
+ ... executable = %(py_path)s
+ ...
+ ... [testdemo]
+ ... recipe = zc.recipe.testrunner
+ ... eggs = demo
+ ... include-site-packages = true
+ ... allowed-eggs-from-site-packages =
+ ... """ % dict(py_path=py_path))
+
+.. ReST comment: Hide the rest of the test from PyPI readers.
+
+ This will fail, because we cannot find demo anywhere (notice we are no
+ longer developing it in the buildout configuration above):
+
+ >>> print system(
+ ... os.path.join(new_buildout, 'bin', 'buildout') + ' -q'),
+ While:
+ Installing testdemo.
+ Getting distribution for 'demo'.
+ Error: Couldn't find a distribution for 'demo'.
+
+ However, if we allow all eggs through, it works, because demo has been
+ installed in the "system Python".
+
+ >>> write(new_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... develop = altdemo
+ ... parts = testdemo
+ ... eggs-directory = tmpeggs
+ ... executable = %(py_path)s
+ ... offline = true
+ ...
+ ... [testdemo]
+ ... recipe = zc.recipe.testrunner
+ ... eggs = demo
+ ... include-site-packages = true
+ ... """ % dict(py_path=py_path))
+
+ >>> print system(
+ ... os.path.join(new_buildout, 'bin', 'buildout') + ' -q'),
+
+
+Like include-site-packages, it is also honored in the main buildout
+section if it is not overridden.
+
+.. ReST comment: hide from PyPI. This will fail again, showing we have
+ blocked the eggs.
+
+ >>> write(new_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = testdemo
+ ... eggs-directory = tmpeggs
+ ... allowed-eggs-from-site-packages =
+ ... executable = %(py_path)s
+ ... offline = true
+ ...
+ ... [testdemo]
+ ... recipe = zc.recipe.testrunner
+ ... eggs = demo
+ ... include-site-packages = true
+ ... """ % dict(py_path=py_path))
+
+ >>> print system(
+ ... os.path.join(new_buildout, 'bin', 'buildout') + ' -q'),
+ While:
+ Installing testdemo.
+ Getting distribution for 'demo'.
+ Error: Couldn't find a distribution for 'demo'.
+
+extends
+-------
+
+The extends option lets you inherit options from other sections. This can
+keep you from repeating yourself. For instance, in this example, the
+testdemo section gets all of its configuration from the source section, except
+it overrides the initialization.
+
+.. ReST comment: we'll move back to the sample_buildout.
+
+ >>> cd(sample_buildout)
+
+..
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... develop = demo
+ ... parts = testdemo
+ ... offline = true
+ ...
+ ... [source]
+ ... eggs = demo
+ ... extra-paths = /usr/local/zope/lib/python
+ ... defaults = ['--tests-pattern', '^f?tests$',
+ ... '-v'
+ ... ]
+ ... initialization = print 'Hello all you egg-laying pythons!'
+ ...
+ ... [testdemo]
+ ... recipe = zc.recipe.testrunner
+ ... extends = source
+ ... initialization = print 'Hello all you egg-laying pythons!'
+ ... print 'I thought pythons were live bearers?'
+ ... """)
+
+.. ReST comment: PyPI readers don't need to see the proof, but here it is.
+
+ >>> print system(os.path.join(sample_buildout, 'bin', 'buildout') + ' -q'),
+
+ >>> cat(sample_buildout, 'bin', 'testdemo')
+ #!/usr/local/bin/python2.4 -S
+ <BLANKLINE>
+ import sys
+ sys.path[0:0] = [
+ '/sample-buildout/parts/testdemo/site-packages',
+ ]
+ <BLANKLINE>
+ <BLANKLINE>
+ import os
+ path = sys.path[0]
+ if os.environ.get('PYTHONPATH'):
+ path = os.pathsep.join([path, os.environ['PYTHONPATH']])
+ os.environ['PYTHONPATH'] = path
+ import site # imports custom buildout-generated site.py
+ import os
+ sys.argv[0] = os.path.abspath(sys.argv[0])
+ os.chdir('/sample-buildout/parts/testdemo/working-directory')
+ print 'Hello all you egg-laying pythons!'
+ print 'I thought pythons were live bearers?'
+ <BLANKLINE>
+ import zope.testrunner
+ <BLANKLINE>
+ if __name__ == '__main__':
+ zope.testrunner.run((['--tests-pattern', '^f?tests$',
+ '-v'
+ ]) + [
+ '--test-path', '/sample-buildout/demo',
+ ])
+
+exec-sitecustomize
+------------------
+
+This option lets you choose to execute the sitecustomize file of the Python
+you are using. It is usually false.
+
+.. ReST comment: here's the demo.
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... develop = demo
+ ... parts = testdemo
+ ... executable = %(py_path)s
+ ...
+ ... [testdemo]
+ ... recipe = zc.recipe.testrunner
+ ... eggs = demo
+ ... exec-sitecustomize = true
+ ... """ % dict(py_path=py_path))
+
+ >>> ignored = system(buildout),
+
+ >>> cat(sample_buildout, 'parts', 'testdemo', 'site-packages',
+ ... 'sitecustomize.py') # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+ <BLANKLINE>
+ # The following is from
+ # /executable_buildout/parts/py/sitecustomize.py
+ ...
+ import os
+ os.environ['zc.buildout'] = 'foo bar baz shazam'
+
+.. _`pertinent section of the zc.buildout documentation`:
+ http://pypi.python.org/pypi/zc.buildout/1.5.0#working-with-a-system-python
+
+
+
Modified: zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/__init__.py
===================================================================
--- zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/__init__.py 2010-08-28 02:18:57 UTC (rev 115977)
+++ zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/__init__.py 2010-08-28 02:44:24 UTC (rev 115978)
@@ -11,9 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""A few built-in recipes
-
-$Id$
+"""A recipe for a zope.testrunner-based testrunner.
"""
import os
@@ -21,7 +19,7 @@
import pkg_resources
import sys
import zc.buildout.easy_install
-import zc.recipe.egg
+import z3c.recipe.scripts.scripts
class TestRunner:
@@ -29,18 +27,23 @@
self.buildout = buildout
self.name = name
self.options = options
+ # We do this early so the "extends" functionality works before we get
+ # to the other options below.
+ self._delegated = z3c.recipe.scripts.scripts.Base(
+ buildout, name, options)
+
options['script'] = os.path.join(buildout['buildout']['bin-directory'],
options.get('script', self.name),
)
if not options.get('working-directory', ''):
options['location'] = os.path.join(
- buildout['buildout']['parts-directory'], name)
- self.egg = zc.recipe.egg.Egg(buildout, name, options)
+ buildout['buildout']['parts-directory'], name,
+ 'working-directory')
def install(self):
options = self.options
- dest = []
- eggs, ws = self.egg.working_set(('zope.testrunner', ))
+ generated = []
+ eggs, ws = self._delegated.working_set(('zope.testrunner', ))
test_paths = [ws.find(pkg_resources.Requirement.parse(spec)).location
for spec in eggs]
@@ -49,19 +52,27 @@
if defaults:
defaults = '(%s) + ' % defaults
+ if not os.path.exists(options['parts-directory']):
+ os.mkdir(options['parts-directory'])
+ generated.append(options['parts-directory'])
+ site_py_dest = os.path.join(options['parts-directory'],
+ 'site-packages')
+ if not os.path.exists(site_py_dest):
+ os.mkdir(site_py_dest)
+ generated.append(site_py_dest)
wd = options.get('working-directory', '')
if not wd:
wd = options['location']
if os.path.exists(wd):
assert os.path.isdir(wd)
else:
- os.mkdir(wd)
- dest.append(wd)
+ os.mkdir(wd) # makedirs
+ generated.append(wd)
wd = os.path.abspath(wd)
- if self.egg._relative_paths:
- wd = _relativize(self.egg._relative_paths, wd)
- test_paths = [_relativize(self.egg._relative_paths, p)
+ if self._delegated._relative_paths:
+ wd = _relativize(self._delegated._relative_paths, wd)
+ test_paths = [_relativize(self._delegated._relative_paths, p)
for p in test_paths]
else:
wd = repr(wd)
@@ -79,21 +90,23 @@
if initialization_section:
initialization += initialization_section
- dest.extend(zc.buildout.easy_install.scripts(
- [(options['script'], 'zope.testrunner', 'run')],
- ws, options['executable'],
- self.buildout['buildout']['bin-directory'],
- extra_paths=self.egg.extra_paths,
- arguments = defaults + (
+ generated.extend(zc.buildout.easy_install.sitepackage_safe_scripts(
+ self.buildout['buildout']['bin-directory'], ws,
+ options['executable'], site_py_dest,
+ reqs=[(options['script'], 'zope.testrunner', 'run')],
+ extra_paths=self._delegated.extra_paths,
+ include_site_packages=self._delegated.include_site_packages,
+ exec_sitecustomize=self._delegated.exec_sitecustomize,
+ relative_paths=self._delegated._relative_paths,
+ script_arguments=defaults + (
'[\n'+
''.join((" '--test-path', %s,\n" % p)
for p in test_paths)
+' ]'),
- initialization = initialization,
- relative_paths = self.egg._relative_paths,
+ script_initialization=initialization,
))
- return dest
+ return generated
update = install
Modified: zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/tests.py
===================================================================
--- zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/tests.py 2010-08-28 02:18:57 UTC (rev 115977)
+++ zc.recipe.testrunner/trunk/src/zc/recipe/testrunner/tests.py 2010-08-28 02:44:24 UTC (rev 115978)
@@ -25,6 +25,7 @@
zc.buildout.testing.buildoutSetUp(test)
zc.buildout.testing.install_develop('zc.recipe.testrunner', test)
zc.buildout.testing.install_develop('zc.recipe.egg', test)
+ zc.buildout.testing.install_develop('z3c.recipe.scripts', test)
zc.buildout.testing.install('zope.testing', test)
zc.buildout.testing.install('zope.testrunner', test)
zc.buildout.testing.install('zope.interface', test)
More information about the checkins
mailing list