Commit 6826e364 authored by Jim Fulton's avatar Jim Fulton

Allow custom python interpreters (other than the one used to run the

buildout) to be used.
parent 6eb9bab7
Installation of distributions as eggs
=====================================
The zc.recipe.egg ewcipe can be used to install various types if
The zc.recipe.egg recipe can be used to install various types if
distutils distributions as eggs. It takes a number of options:
distribution
......@@ -14,6 +14,18 @@ distribution
find-links
A list of URLs, files, or directories to search for distributions.
python
The name of a section to get the Python executable from.
If not specified, then the buildout python option is used. The
Python executable is found in the executable option of the named
section.
unzip
The value of this option must be either true or false. If the value
is true, then the installed egg will be unzipped. Note that this is
only effective when an egg is installed. If a zipped egg already
exists in the eggs directory, it will not be unzipped.
To illustrate this, we've created a directory with some sample eggs:
>>> ls(sample_eggs)
......@@ -51,7 +63,6 @@ Now, if we look at the buildout eggs directory:
>>> ls(sample_buildout, 'eggs')
- demo-0.2-py2.3.egg
- demoneeded-1.0-py2.3.egg
- zc.recipe.egg.egg-link
We see that we got an egg for demo that met the requirement, as well
as the egg for demoneeded, wich demo requires. (We also see an egg
......@@ -94,7 +105,7 @@ the bits if the path added to reflect the eggs:
<BLANKLINE>
The recipe gets the most recent distribution that satisfies the
specification. For example, if we remove the restriction on demo:
specification. For example, We remove the restriction on demo:
>>> write(sample_buildout, 'buildout.cfg',
... """
......@@ -104,9 +115,11 @@ specification. For example, if we remove the restriction on demo:
... [demo]
... recipe = zc.recipe.egg
... find-links = %s
... unzip = true
... """ % sample_eggs)
and rerun the buildout:
We also used the unzip uption to request a directory, rather than
a zip file.
>>> print system(runscript),
......@@ -114,9 +127,8 @@ Then we'll get a new demo egg:
>>> ls(sample_buildout, 'eggs')
- demo-0.2-py2.3.egg
- demo-0.3-py2.3.egg
d demo-0.3-py2.3.egg
- demoneeded-1.0-py2.3.egg
- zc.recipe.egg.egg-link
Note that we removed the distribution option, and the distribution
defaulted to the part name.
......@@ -150,7 +162,6 @@ arguments:
You can also control the name used for scripts:
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
......@@ -167,3 +178,4 @@ You can also control the name used for scripts:
>>> ls(sample_buildout, 'bin')
- buildout
- foo
......@@ -16,7 +16,7 @@
$Id$
"""
import os
import os, zipfile
import zc.buildout.egglinker
import zc.buildout.easy_install
......@@ -41,12 +41,20 @@ class Egg:
options['_e'] = buildout['buildout']['eggs-directory']
options['_d'] = buildout['buildout']['develop-eggs-directory']
assert options.get('unzip') in ('true', 'false', None)
python = options.get('python', buildout['buildout']['python'])
options['executable'] = buildout[python]['executable']
def install(self):
options = self.options
distribution = options.get('distribution', self.name)
zc.buildout.easy_install.install(
distribution, options['_e'], self.links)
distribution, options['_e'], self.links, options['executable'],
always_unzip=options.get('unzip') == 'true')
eggss = [options['_d'], options['_e']]
scripts = options.get('scripts')
if scripts or scripts is None:
if scripts is not None:
......@@ -56,6 +64,6 @@ class Egg:
for s in scripts
])
return zc.buildout.egglinker.scripts(
[distribution],
options['_b'], [options['_d'], options['_e']], scripts=scripts)
[distribution], options['_b'], eggss,
scripts=scripts, executable=options['executable'])
Controlling which Python to use
-------------------------------
The following assumes that your $HOME/.buildout/default.cfg has
python2.3 and python2.4 sections that define Python 2.3 and Python 2.4
executables.
We can specify the python to use by specifying the name of a section
to read the Python executable from. The default is the section
defined by the python buildout option.
We have a directory with some sample eggs:
>>> ls(sample_eggs)
- demo-0.1-py2.3.egg
- demo-0.1-py2.4.egg
- demo-0.2-py2.3.egg
- demo-0.2-py2.4.egg
- demo-0.3-py2.3.egg
- demo-0.3-py2.4.egg
- demoneeded-1.0-py2.3.egg
- demoneeded-1.0-py2.4.egg
We have a sample buildout. Let's update it's configuration file to
install the demo package using Python 2.3.
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = demo
... eggs-directory = eggs
...
... [demo]
... recipe = zc.recipe.egg
... distribution = demo <0.3
... find-links = %s
... python = python2.3
... """ % sample_eggs)
In our default.cfg file in the .buildout subdirectiry of our
directory, we have something like::
[python2.3]
executable = /usr/bin/python
[python2.4]
executable = /usr/local/bin/python2.4
(Of course, the paths will vary from system to system.)
Now, if we run the buildout:
>>> import os
>>> os.chdir(sample_buildout)
>>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
>>> print system(buildout),
we'll get the Python 2.3 eggs for demo and demoneeded:
>>> ls(sample_buildout, 'eggs')
- demo-0.2-py2.3.egg
- demoneeded-1.0-py2.3.egg
And the generated scripts invoke Python 2.3:
>>> f = open(os.path.join(sample_buildout, 'bin', 'demo'))
>>> f.readline().strip() == '#!' + python2_3_executable
True
>>> print f.read(),
<BLANKLINE>
import sys
sys.path[0:0] = [
'/private/tmp/tmpOEtRO8sample-buildout/eggs/demo-0.2-py2.3.egg',
'/private/tmp/tmpOEtRO8sample-buildout/eggs/demoneeded-1.0-py2.3.egg'
]
<BLANKLINE>
import eggrecipedemo
<BLANKLINE>
if __name__ == '__main__':
eggrecipedemo.main()
>>> f = open(os.path.join(sample_buildout, 'bin', 'py_demo'))
>>> f.readline().strip() == '#!' + python2_3_executable + ' -i'
True
>>> print f.read(),
<BLANKLINE>
import sys
sys.path[0:0] = [
'/tmp/tmpOBTxDMsample-buildout/eggs/demo-0.2-py2.3.egg',
'/tmp/tmpOBTxDMsample-buildout/eggs/demoneeded-1.0-py2.3.egg'
]
If we change the Python version to 2.4, we'll use Python 2.4 eggs:
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = demo
... eggs-directory = eggs
...
... [demo]
... recipe = zc.recipe.egg
... distribution = demo <0.3
... find-links = %s
... python = python2.4
... """ % sample_eggs)
>>> print system(buildout),
>>> ls(sample_buildout, 'eggs')
- demo-0.2-py2.3.egg
- demo-0.2-py2.4.egg
- demoneeded-1.0-py2.3.egg
- demoneeded-1.0-py2.4.egg
>>> f = open(os.path.join(sample_buildout, 'bin', 'demo'))
>>> f.readline().strip() == '#!' + python2_4_executable
True
>>> print f.read(),
<BLANKLINE>
import sys
sys.path[0:0] = [
'/private/tmp/tmpOEtRO8sample-buildout/eggs/demo-0.2-py2.4.egg',
'/private/tmp/tmpOEtRO8sample-buildout/eggs/demoneeded-1.0-py2.4.egg'
]
<BLANKLINE>
import eggrecipedemo
<BLANKLINE>
if __name__ == '__main__':
eggrecipedemo.main()
>>> f = open(os.path.join(sample_buildout, 'bin', 'py_demo'))
>>> f.readline().strip() == '#!' + python2_4_executable + ' -i'
True
>>> print f.read(),
<BLANKLINE>
import sys
sys.path[0:0] = [
'/tmp/tmpOBTxDMsample-buildout/eggs/demo-0.2-py2.4.egg',
'/tmp/tmpOBTxDMsample-buildout/eggs/demoneeded-1.0-py2.4.egg'
]
......@@ -26,14 +26,22 @@ def dirname(d, level=1):
def setUp(test):
zc.buildout.testing.buildoutSetUp(test)
open(os.path.join(test.globs['sample_buildout'],
'eggs', 'zc.recipe.egg.egg-link'),
'develop-eggs', 'zc.recipe.egg.egg-link'),
'w').write(dirname(__file__, 4))
zc.buildout.testing.create_sample_eggs(test)
def tearDown(test):
shutil.rmtree(test.globs['_sample_eggs_container'])
zc.buildout.testing.buildoutTearDown(test)
def setUpPython(test):
zc.buildout.testing.buildoutSetUp(test, clear_home=False)
open(os.path.join(test.globs['sample_buildout'],
'develop-eggs', 'zc.recipe.egg.egg-link'),
'w').write(dirname(__file__, 4))
zc.buildout.testing.multi_python(test)
def test_suite():
return unittest.TestSuite((
......@@ -49,7 +57,15 @@ def test_suite():
'\\2-VVV-egg')
])
),
doctest.DocFileSuite(
'selecting-python.txt',
setUp=setUpPython, tearDown=tearDown,
checker=renormalizing.RENormalizing([
(re.compile('\S+sample-(\w+)%s(\S+)' % os.path.sep),
r'/sample-\1/\2'),
(re.compile('\S+sample-(\w+)'), r'/sample-\1'),
]),
),
))
if __name__ == '__main__':
......
......@@ -22,11 +22,16 @@ $Id$
import os, sys
def install(spec, dest, links, python=sys.executable):
def install(spec, dest, links, executable=sys.executable, always_unzip=False):
prefix = sys.exec_prefix + os.path.sep
path = os.pathsep.join([p for p in sys.path if not p.startswith(prefix)])
os.spawnle(
os.P_WAIT, python, python,
args = (
'-c', 'from setuptools.command.easy_install import main; main()',
'-mqxd', dest, '-f', ' '.join(links), spec,
dict(PYTHONPATH=path))
'-mqxd', dest)
if links:
args += ('-f', ' '.join(links))
if always_unzip:
args += ('-Z', )
args += (spec, dict(PYTHONPATH=path))
os.spawnle(os.P_WAIT, executable, executable, *args)
......@@ -20,9 +20,13 @@ For example, given the sample eggs:
>>> ls(sample_eggs)
- demo-0.1-py2.3.egg
- demo-0.1-py2.4.egg
- demo-0.2-py2.3.egg
- demo-0.2-py2.4.egg
- demo-0.3-py2.3.egg
- demo-0.3-py2.4.egg
- demoneeded-1.0-py2.3.egg
- demoneeded-1.0-py2.4.egg
let's make directory and install the demo egg to it:
......@@ -34,3 +38,28 @@ let's make directory and install the demo egg to it:
- demo-0.3-py2.3.egg
- demoneeded-1.0-py2.3.egg
We can specify an alternate Python executable, and we can specify
that, when we retrieve (or create) an egg, it should be unzipped.
>>> import shutil
>>> shutil.rmtree(dest)
>>> dest = tempfile.mkdtemp()
>>> zc.buildout.easy_install.install(
... 'demo', dest, [sample_eggs],
... always_unzip=True, executable= python2_3_executable)
>>> ls(dest)
d demo-0.3-py2.3.egg
d demoneeded-1.0-py2.3.egg
>>> shutil.rmtree(dest)
>>> dest = tempfile.mkdtemp()
>>> zc.buildout.easy_install.install(
... 'demo', dest, [sample_eggs],
... always_unzip=True, executable= python2_4_executable)
>>> ls(dest)
d demo-0.3-py2.4.egg
d demoneeded-1.0-py2.4.egg
......@@ -25,28 +25,44 @@ $Id$
# XXX need to deal with extras
import os
import re
import sys
import pkg_resources
def distributions(reqs, eggss):
env = pkg_resources.Environment(eggss)
_versions = {sys.executable: '%d.%d' % sys.version_info[:2]}
def _get_version(executable):
try:
return _versions[executable]
except KeyError:
i, o = os.popen4(executable + ' -V')
i.close()
version = o.read().strip()
o.close()
pystring, version = version.split()
assert pystring == 'Python'
version = re.match('(\d[.]\d)[.]\d$', version).group(1)
_versions[executable] = version
return version
def distributions(reqs, eggss, executable=sys.executable):
env = pkg_resources.Environment(eggss, python=_get_version(executable))
ws = pkg_resources.WorkingSet()
reqs = [pkg_resources.Requirement.parse(r) for r in reqs]
return ws.resolve(reqs, env=env)
def path(reqs, eggss):
dists = distributions(reqs, eggss)
def path(reqs, eggss, executable=sys.executable):
dists = distributions(reqs, eggss, executable)
return [dist.location for dist in dists]
def location(spec, eggss):
env = pkg_resources.Environment(eggss)
def location(spec, eggss, executable=sys.executable):
env = pkg_resources.Environment(eggss, python=_get_version(executable))
req = pkg_resources.Requirement.parse(spec)
dist = env.best_match(req, pkg_resources.WorkingSet())
return dist.location
def scripts(reqs, dest, eggss, scripts=None):
dists = distributions(reqs, eggss)
def scripts(reqs, dest, eggss, scripts=None, executable=sys.executable):
dists = distributions(reqs, eggss, executable)
reqs = [pkg_resources.Requirement.parse(r) for r in reqs]
projects = [r.project_name for r in reqs]
path = "',\n '".join([dist.location for dist in dists])
......@@ -64,7 +80,7 @@ def scripts(reqs, dest, eggss, scripts=None):
sname = os.path.join(dest, sname)
generated.append(sname)
_script(dist, 'console_scripts', name, path, sname)
_script(dist, 'console_scripts', name, path, sname, executable)
name = 'py_'+dist.project_name
if scripts is not None:
......@@ -75,14 +91,14 @@ def scripts(reqs, dest, eggss, scripts=None):
if sname is not None:
sname = os.path.join(dest, sname)
generated.append(sname)
_pyscript(path, sname)
_pyscript(path, sname, executable)
return generated
def _script(dist, group, name, path, dest):
def _script(dist, group, name, path, dest, executable):
entry_point = dist.get_entry_info(group, name)
open(dest, 'w').write(script_template % dict(
python = sys.executable,
python = executable,
path = path,
project = dist.project_name,
name = name,
......@@ -109,9 +125,9 @@ if __name__ == '__main__':
'''
def _pyscript(path, dest):
def _pyscript(path, dest, executable):
open(dest, 'w').write(py_script_template % dict(
python = sys.executable,
python = executable,
path = path,
))
try:
......
......@@ -17,9 +17,13 @@ We have a directory with some sample eggs in it:
>>> ls(sample_eggs)
- demo-0.1-py2.3.egg
- demo-0.1-py2.4.egg
- demo-0.2-py2.3.egg
- demo-0.2-py2.4.egg
- demo-0.3-py2.3.egg
- demo-0.3-py2.4.egg
- demoneeded-1.0-py2.3.egg
- demoneeded-1.0-py2.4.egg
The demo package depends on the demoneeded package.
......@@ -66,8 +70,8 @@ The demo script run the entry point defined in the demo egg:
<BLANKLINE>
import sys
sys.path[0:0] = [
'/tmp/tmpuR5-n7eggtest/dist/demo-0.1-py2.3.egg',
'/tmp/tmpuR5-n7eggtest/dist/demoneeded-1.0-py2.3.egg'
'/tmp/xyzsample-eggs/demo-0.1-py2.3.egg',
'/tmp/xyzsample-eggs/demoneeded-1.0-py2.3.egg'
]
<BLANKLINE>
import eggrecipedemo
......@@ -90,8 +94,8 @@ the path set:
<BLANKLINE>
import sys
sys.path[0:0] = [
'/tmp/tmpuR5-n7eggtest/dist/demo-0.1-py2.3.egg',
'/tmp/tmpuR5-n7eggtest/dist/demoneeded-1.0-py2.3.egg'
'/tmp/xyzsample-eggs/demo-0.1-py2.3.egg',
'/tmp/xyzsample-eggs/demoneeded-1.0-py2.3.egg'
]
An additional argumnet can be passed to define which scripts to install
......@@ -112,8 +116,6 @@ original script names to new script names.
>>> print system(os.path.join(bin, 'run')),
1 1
>>> shutil.rmtree(bin)
Sometimes we need more control over script generation. Some
lower-level APIs are available to help us generate scripts ourselves.
These apis are a little bit higher level than those provided by
......@@ -124,15 +126,15 @@ of requirements from a sequence of egg directories:
>>> zc.buildout.egglinker.path(['demo==0.1'], [sample_eggs])
... # doctest: +NORMALIZE_WHITESPACE
['/tmp/tmpQeJjpkeggtest/dist/demo-0.1-py2.4.egg',
'/tmp/tmpQeJjpkeggtest/dist/demoneeded-1.0-py2.4.egg']
['/tmp/xyzsample-eggs/demo-0.1-py2.3.egg',
'/tmp/xyzsample-eggs/demoneeded-1.0-py2.3.egg']
The location method returns the distribution location for an egg that
satisfies a requirement:
>>> zc.buildout.egglinker.location('demo==0.1', [sample_eggs])
'/tmp/tmpQeJjpkeggtest/dist/demo-0.1-py2.4.egg'
'/tmp/xyzsample-eggs/demo-0.1-py2.3.egg'
The distributions function can retrieve a list of distributions found
ineg directories that match a sequence of requirements:
......@@ -141,3 +143,73 @@ ineg directories that match a sequence of requirements:
... zc.buildout.egglinker.distributions(['demo==0.1'], [sample_eggs])]
[('demo', '0.1'), ('demoneeded', '1.0')]
Using a custom Python interpreter
---------------------------------
You can pass an executable argument to egglinker methods:
>>> scripts = zc.buildout.egglinker.scripts(
... ['demo==0.1'], bin, [sample_eggs],
... executable=python2_3_executable)
>>> f = open(os.path.join(bin, 'demo'))
>>> f.readline().strip() == '#!' + python2_3_executable
True
>>> print f.read(),
<BLANKLINE>
import sys
sys.path[0:0] = [
'/tmp/sample-eggs/dist/demo-0.1-py2.3.egg',
'/tmp/sample-eggs/dist/demoneeded-1.0-py2.3.egg'
]
<BLANKLINE>
import eggrecipedemo
<BLANKLINE>
if __name__ == '__main__':
eggrecipedemo.main()
>>> zc.buildout.egglinker.path(['demo==0.1'], [sample_eggs],
... python2_3_executable)
... # doctest: +NORMALIZE_WHITESPACE
['/tmp/sample-eggs/dist/demo-0.1-py2.3.egg',
'/tmp/sample-eggs/dist/demoneeded-1.0-py2.3.egg']
>>> zc.buildout.egglinker.location('demo==0.1', [sample_eggs],
... python2_3_executable)
'/tmp/sample-eggs/demo-0.1-py2.3.egg'
>>> [(d.project_name, d.version) for d in
... zc.buildout.egglinker.distributions(
... ['demo==0.1'], [sample_eggs], python2_3_executable)]
[('demo', '0.1'), ('demoneeded', '1.0')]
>>> scripts = zc.buildout.egglinker.scripts(
... ['demo==0.1'], bin, [sample_eggs],
... executable=python2_4_executable)
>>> f = open(os.path.join(bin, 'demo'))
>>> f.readline().strip() == '#!' + python2_4_executable
True
>>> print f.read(),
<BLANKLINE>
import sys
sys.path[0:0] = [
'/tmp/sample-eggs/dist/demo-0.1-py2.4.egg',
'/tmp/sample-eggs/dist/demoneeded-1.0-py2.4.egg'
]
<BLANKLINE>
import eggrecipedemo
<BLANKLINE>
if __name__ == '__main__':
eggrecipedemo.main()
>>> zc.buildout.egglinker.path(['demo==0.1'], [sample_eggs],
... python2_4_executable)
... # doctest: +NORMALIZE_WHITESPACE
['/tmp/sample-eggs/dist/demo-0.1-py2.4.egg',
'/tmp/sample-eggs/dist/demoneeded-1.0-py2.4.egg']
>>> shutil.rmtree(bin)
......@@ -11,12 +11,12 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""XXX short summary goes here.
"""Various test-support utility functions
$Id$
"""
import os, re, shutil, sys, tempfile, unittest
import ConfigParser, os, re, shutil, sys, tempfile, unittest
from zope.testing import doctest, renormalizing
import pkg_resources
......@@ -52,10 +52,11 @@ def system(command, input=''):
i.close()
return o.read()
def buildoutSetUp(test):
# we both need to make sure that HOME isn't set and be prepared
# to restore whatever it was after the test.
test.globs['_oldhome'] = os.environ.pop('HOME', None)
def buildoutSetUp(test, clear_home=True):
if clear_home:
# we both need to make sure that HOME isn't set and be prepared
# to restore whatever it was after the test.
test.globs['_oldhome'] = os.environ.pop('HOME', None)
sample = tempfile.mkdtemp('sample-buildout')
for name in ('bin', 'eggs', 'develop-eggs', 'parts'):
......@@ -96,7 +97,7 @@ def buildoutSetUp(test):
def buildoutTearDown(test):
shutil.rmtree(test.globs['sample_buildout'])
os.chdir(test.globs['__original_wd__'])
if test.globs['_oldhome'] is not None:
if test.globs.get('_oldhome') is not None:
os.environ['HOME'] = test.globs['_oldhome']
......@@ -110,12 +111,12 @@ from pkg_resources import load_entry_point
sys.exit(load_entry_point('zc.buildout', 'console_scripts', 'buildout')())
'''
def runsetup(d):
def runsetup(d, executable):
here = os.getcwd()
try:
os.chdir(d)
os.spawnle(
os.P_WAIT, sys.executable, sys.executable,
os.P_WAIT, executable, executable,
'setup.py', '-q', 'bdist_egg',
{'PYTHONPATH': os.path.dirname(pkg_resources.__file__)},
)
......@@ -123,20 +124,25 @@ def runsetup(d):
finally:
os.chdir(here)
def create_sample_eggs(test):
sample = tempfile.mkdtemp('sample-eggs')
test.globs['_sample_eggs_container'] = sample
test.globs['sample_eggs'] = os.path.join(sample, 'dist')
write(sample, 'README.txt', '')
def create_sample_eggs(test, executable=sys.executable):
if '_sample_eggs_container' in test.globs:
sample = test.globs['_sample_eggs_container']
else:
sample = tempfile.mkdtemp('sample-eggs')
test.globs['_sample_eggs_container'] = sample
test.globs['sample_eggs'] = os.path.join(sample, 'dist')
write(sample, 'README.txt', '')
write(sample, 'eggrecipedemobeeded.py', 'y=1\n')
write(
sample, 'setup.py',
"from setuptools import setup\n"
"setup(name='demoneeded', py_modules=['eggrecipedemobeeded'],"
" zip_safe=True, version='1.0')\n"
)
runsetup(sample)
)
runsetup(sample, executable)
os.remove(os.path.join(sample, 'eggrecipedemobeeded.py'))
for i in (1, 2, 3):
write(
sample, 'eggrecipedemo.py',
......@@ -152,4 +158,17 @@ def create_sample_eggs(test):
" entry_points={'console_scripts': ['demo = eggrecipedemo:main']},"
" zip_safe=True, version='0.%s')\n" % i
)
runsetup(sample)
runsetup(sample, executable)
def multi_python(test):
defaults = ConfigParser.RawConfigParser()
defaults.readfp(open(os.path.join(os.environ['HOME'],
'.buildout', 'default.cfg')))
p23 = defaults.get('python2.3', 'executable')
p24 = defaults.get('python2.4', 'executable')
create_sample_eggs(test, executable=p23)
create_sample_eggs(test, executable=p24)
test.globs['python2_3_executable'] = p23
test.globs['python2_4_executable'] = p24
......@@ -64,8 +64,8 @@ It is an error to create a variable-reference cycle:
'''
def linkerSetUp(test):
zc.buildout.testing.buildoutSetUp(test)
zc.buildout.testing.create_sample_eggs(test)
zc.buildout.testing.buildoutSetUp(test, clear_home=False)
zc.buildout.testing.multi_python(test)
def linkerTearDown(test):
shutil.rmtree(test.globs['_sample_eggs_container'])
......@@ -75,6 +75,61 @@ def buildoutTearDown(test):
shutil.rmtree(test.globs['extensions'])
shutil.rmtree(test.globs['home'])
zc.buildout.testing.buildoutTearDown(test)
class PythonNormalizing(renormalizing.RENormalizing):
def _transform(self, want, got):
if '/xyzsample-eggs/' in want:
got = got.replace('-py2.4.egg', '-py2.3.egg')
firstg = got.split('\n')[0]
firstw = want.split('\n')[0]
if firstg.startswith('#!') and firstw.startswith('#!'):
firstg = ' '.join(firstg.split()[1:])
got = firstg + '\n' + '\n'.join(got.split('\n')[1:])
firstw = ' '.join(firstw.split()[1:])
want = firstw + '\n' + '\n'.join(want.split('\n')[1:])
for pattern, repl in self.patterns:
want = pattern.sub(repl, want)
got = pattern.sub(repl, got)
return want, got
def check_output(self, want, got, optionflags):
if got == want:
return True
want, got = self._transform(want, got)
if got == want:
return True
return doctest.OutputChecker.check_output(self, want, got, optionflags)
def output_difference(self, example, got, optionflags):
want = example.want
# If want is empty, use original outputter. This is useful
# when setting up tests for the first time. In that case, we
# generally use the differencer to display output, which we evaluate
# by hand.
if not want.strip():
return doctest.OutputChecker.output_difference(
self, example, got, optionflags)
# Dang, this isn't as easy to override as we might wish
original = want
want, got = self._transform(want, got)
# temporarily hack example with normalized want:
example.want = want
result = doctest.OutputChecker.output_difference(
self, example, got, optionflags)
example.want = original
return result
def test_suite():
return unittest.TestSuite((
......@@ -86,22 +141,23 @@ def test_suite():
(re.compile('__buildout_signature__ = recipes-\S+'),
'__buildout_signature__ = recipes-SSSSSSSSSSS'),
(re.compile('\S+sample-(\w+)%s(\S+)' % os.path.sep),
r'/sample-\1/\3'),
(re.compile('\S+sample-(\w+)'),
r'/sample-\1/\3'),
(re.compile('executable = \S+python\S*'), 'executable = python'),
r'/sample-\1/\2'),
(re.compile('\S+sample-(\w+)'), r'/sample-\1'),
(re.compile('executable = \S+python\S*'),
'executable = python'),
])
),
doctest.DocFileSuite(
'egglinker.txt', 'easy_install.txt',
setUp=linkerSetUp, tearDown=linkerTearDown,
checker=renormalizing.RENormalizing([
(re.compile('(\S+[/%(sep)s]| )'
'(\\w+-)[^ \t\n%(sep)s/]+.egg'
% dict(sep=os.path.sep)
),
'\\2-VVV-egg'),
(re.compile('\S+%spython(\d.\d)?' % os.path.sep), 'python')
checker=PythonNormalizing([
(re.compile("'%(sep)s\S+sample-eggs%(sep)s(dist%(sep)s)?"
% dict(sep=os.path.sep)),
'/sample-eggs/'),
(re.compile("(- demo(needed)?-\d[.]\d-py)\d[.]\d[.]egg"),
'\\1V.V.egg'),
]),
),
doctest.DocTestSuite(
......
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