Commit dc32780e authored by Jim Fulton's avatar Jim Fulton

Tests pass on Python 2.7 with setuptools 8

parent 380ae506
...@@ -35,7 +35,7 @@ Bootstraps a buildout-based project. ...@@ -35,7 +35,7 @@ Bootstraps a buildout-based project.
Simply run this script in a directory containing a buildout.cfg, using the Simply run this script in a directory containing a buildout.cfg, using the
Python that you want bin/buildout to use. Python that you want bin/buildout to use.
Note that by using --find-links to point to local resources, you can keep Note that by using --find-links to point to local resources, you can keep
this script from going over the network. this script from going over the network.
''' '''
...@@ -59,7 +59,8 @@ parser.add_option("-f", "--find-links", ...@@ -59,7 +59,8 @@ parser.add_option("-f", "--find-links",
parser.add_option("--allow-site-packages", parser.add_option("--allow-site-packages",
action="store_true", default=False, action="store_true", default=False,
help=("Let bootstrap.py use existing site packages")) help=("Let bootstrap.py use existing site packages"))
parser.add_option("--setuptools-version", help="use a specific setuptools version") parser.add_option("--setuptools-version",
help="use a specific setuptools version")
options, args = parser.parse_args() options, args = parser.parse_args()
...@@ -80,10 +81,10 @@ exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez) ...@@ -80,10 +81,10 @@ exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
if not options.allow_site_packages: if not options.allow_site_packages:
# ez_setup imports site, which adds site packages # ez_setup imports site, which adds site packages
# this will remove them from the path to ensure that incompatible versions # this will remove them from the path to ensure that incompatible versions
# of setuptools are not in the path # of setuptools are not in the path
import site import site
# inside a virtualenv, there is no 'getsitepackages'. # inside a virtualenv, there is no 'getsitepackages'.
# We can't remove these reliably # We can't remove these reliably
if hasattr(site, 'getsitepackages'): if hasattr(site, 'getsitepackages'):
for sitepackage_path in site.getsitepackages(): for sitepackage_path in site.getsitepackages():
...@@ -133,10 +134,15 @@ if version is None and not options.accept_buildout_test_releases: ...@@ -133,10 +134,15 @@ if version is None and not options.accept_buildout_test_releases:
_final_parts = '*final-', '*final' _final_parts = '*final-', '*final'
def _final_version(parsed_version): def _final_version(parsed_version):
for part in parsed_version: try:
if (part[:1] == '*') and (part not in _final_parts): return not parsed_version.is_prerelease
return False except AttributeError:
return True # Older setuptools
for part in parsed_version:
if (part[:1] == '*') and (part not in _final_parts):
return False
return True
index = setuptools.package_index.PackageIndex( index = setuptools.package_index.PackageIndex(
search_path=[setuptools_path]) search_path=[setuptools_path])
if find_links: if find_links:
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
# #
############################################################################## ##############################################################################
name = "zc.buildout" name = "zc.buildout"
version = "2.2.5" version = "2.3.dev0"
import os import os
from setuptools import setup from setuptools import setup
...@@ -88,7 +88,7 @@ setup( ...@@ -88,7 +88,7 @@ setup(
package_dir = {'': 'src'}, package_dir = {'': 'src'},
namespace_packages = ['zc'], namespace_packages = ['zc'],
install_requires = [ install_requires = [
'setuptools>=3.3', 'setuptools>=8.0',
], ],
include_package_data = True, include_package_data = True,
entry_points = entry_points, entry_points = entry_points,
......
...@@ -93,11 +93,11 @@ Let's make sure the generated `buildout` script uses it:: ...@@ -93,11 +93,11 @@ Let's make sure the generated `buildout` script uses it::
Now trying the `--setuptools-version` option, that let you define a version for Now trying the `--setuptools-version` option, that let you define a version for
`setuptools`. `setuptools`.
Now let's try with `5.3`, which happens to exist:: Now let's try with `8.0`, which happens to exist::
>>> print_('X'); print_(system( >>> print_('X'); print_(system(
... zc.buildout.easy_install._safe_arg(sys.executable)+' '+ ... zc.buildout.easy_install._safe_arg(sys.executable)+' '+
... 'bootstrap.py --setuptools-version 5.3')); print_('X') ... 'bootstrap.py --setuptools-version 8.0')); print_('X')
... # doctest: +ELLIPSIS ... # doctest: +ELLIPSIS
X...Generated script '/sample/bin/buildout'...X X...Generated script '/sample/bin/buildout'...X
...@@ -106,7 +106,7 @@ Let's make sure the generated `buildout` script uses it:: ...@@ -106,7 +106,7 @@ Let's make sure the generated `buildout` script uses it::
>>> print_(open(buildout_script).read()) # doctest: +ELLIPSIS >>> print_(open(buildout_script).read()) # doctest: +ELLIPSIS
#... #...
sys.path[0:0] = [ sys.path[0:0] = [
'/sample/eggs/setuptools-5.3...egg', '/sample/eggs/setuptools-8.0...egg',
'/sample/eggs/zc.buildout-...egg', '/sample/eggs/zc.buildout-...egg',
]... ]...
...@@ -115,7 +115,7 @@ which happens to exist:: ...@@ -115,7 +115,7 @@ which happens to exist::
>>> print_('X'); print_(system( >>> print_('X'); print_(system(
... zc.buildout.easy_install._safe_arg(sys.executable)+' '+ ... zc.buildout.easy_install._safe_arg(sys.executable)+' '+
... 'bootstrap.py --setuptools-version 5.3 --version 2.0.0')); print_('X') ... 'bootstrap.py --setuptools-version 8.0 --version 2.0.0')); print_('X')
... # doctest: +ELLIPSIS ... # doctest: +ELLIPSIS
X...Generated script '/sample/bin/buildout'...X X...Generated script '/sample/bin/buildout'...X
...@@ -124,6 +124,6 @@ Let's make sure the generated `buildout` script uses it:: ...@@ -124,6 +124,6 @@ Let's make sure the generated `buildout` script uses it::
>>> print_(open(buildout_script).read()) # doctest: +ELLIPSIS >>> print_(open(buildout_script).read()) # doctest: +ELLIPSIS
#... #...
sys.path[0:0] = [ sys.path[0:0] = [
'/sample/eggs/setuptools-5.3...egg', '/sample/eggs/setuptools-8.0...egg',
'/sample/eggs/zc.buildout-2.0.0...egg', '/sample/eggs/zc.buildout-2.0.0...egg',
]... ]...
...@@ -421,10 +421,10 @@ class Installer: ...@@ -421,10 +421,10 @@ class Installer:
# Now find the best one: # Now find the best one:
best = [] best = []
bestv = () bestv = None
for dist in dists: for dist in dists:
distv = dist.parsed_version distv = dist.parsed_version
if distv > bestv: if bestv is None or distv > bestv:
best = [dist] best = [dist]
bestv = distv bestv = distv
elif distv == bestv: elif distv == bestv:
...@@ -1350,9 +1350,13 @@ class VersionConflict(zc.buildout.UserError): ...@@ -1350,9 +1350,13 @@ class VersionConflict(zc.buildout.UserError):
result = ["There is a version conflict.", result = ["There is a version conflict.",
"We already have: %s" % existing_dist, "We already have: %s" % existing_dist,
] ]
stated = False
for dist in self.ws: for dist in self.ws:
if req in dist.requires(): if req in dist.requires():
result.append("but %s requires %r." % (dist, str(req))) result.append("but %s requires %r." % (dist, str(req)))
stated = True
if not stated:
result.append("We require %s" % req)
return '\n'.join(result) return '\n'.join(result)
...@@ -1398,10 +1402,7 @@ def _fix_file_links(links): ...@@ -1398,10 +1402,7 @@ def _fix_file_links(links):
_final_parts = '*final-', '*final' _final_parts = '*final-', '*final'
def _final_version(parsed_version): def _final_version(parsed_version):
for part in parsed_version: return not parsed_version.is_prerelease
if (part[:1] == '*') and (part not in _final_parts):
return False
return True
def redo_pyc(egg): def redo_pyc(egg):
if not os.path.isdir(egg): if not os.path.isdir(egg):
...@@ -1438,13 +1439,22 @@ def redo_pyc(egg): ...@@ -1438,13 +1439,22 @@ def redo_pyc(egg):
call_subprocess(args) call_subprocess(args)
def _constrained_requirement(constraint, requirement): def _constrained_requirement(constraint, requirement):
return pkg_resources.Requirement.parse( if constraint[0] not in '<>':
"%s[%s]%s" % ( if constraint.startswith('='):
requirement.project_name, assert constraint.startswith('==')
','.join(requirement.extras), constraint = constraint[2:]
_constrained_requirement_constraint(constraint, requirement) if constraint not in requirement:
bad_constraint(constraint, requirement)
constraint = '==' + constraint
if requirement.specs:
return pkg_resources.Requirement.parse(
str(requirement) + ',' + constraint
)
else:
return pkg_resources.Requirement.parse(
str(requirement) + ' ' + constraint
) )
)
class IncompatibleConstraintError(zc.buildout.UserError): class IncompatibleConstraintError(zc.buildout.UserError):
"""A specified version is incompatible with a given requirement. """A specified version is incompatible with a given requirement.
...@@ -1456,91 +1466,3 @@ def bad_constraint(constraint, requirement): ...@@ -1456,91 +1466,3 @@ def bad_constraint(constraint, requirement):
logger.error("The constraint, %s, is not consistent with the " logger.error("The constraint, %s, is not consistent with the "
"requirement, %r.", constraint, str(requirement)) "requirement, %r.", constraint, str(requirement))
raise IncompatibleConstraintError("Bad constraint", constraint, requirement) raise IncompatibleConstraintError("Bad constraint", constraint, requirement)
_parse_constraint = re.compile(r'([<>]=?)\s*(\S+)').match
_comparef = {
'>' : lambda x, y: x > y,
'>=': lambda x, y: x >= y,
'<' : lambda x, y: x < y,
'<=': lambda x, y: x <= y,
}
_opop = {'<': '>', '>': '<'}
_opeqop = {'<': '>=', '>': '<='}
def _constrained_requirement_constraint(constraint, requirement):
# Simple cases:
# No specs to merge with:
if not requirement.specs:
if not constraint[0] in '<=>':
constraint = '==' + constraint
return constraint
# Simple single-version constraint:
if constraint[0] not in '<>':
if constraint.startswith('='):
assert constraint.startswith('==')
constraint = constraint[2:]
if constraint in requirement:
return '=='+constraint
bad_constraint(constraint, requirement)
# OK, we have a complex constraint (<. <=, >=, or >) and specs.
# In many cases, the spec needs to filter constraints.
# In other cases, the constraints need to limit the constraint.
specs = requirement.specs
cop, cv = _parse_constraint(constraint).group(1, 2)
pcv = pkg_resources.parse_version(cv)
# Special case, all of the specs are == specs:
if not [op for (op, v) in specs if op != '==']:
# There aren't any non-== specs.
# See if any of the specs satisfy the constraint:
specs = [op+v for (op, v) in specs
if _comparef[cop](pkg_resources.parse_version(v), pcv)]
if specs:
return ','.join(specs)
bad_constraint(constraint, requirement)
cop0 = cop[0]
# Normalize specs by splitting >= and <= specs. We need to do this
# because these have really weird semantics. Also cache parsed
# versions, which we'll need for comparisons:
specs = []
for op, v in requirement.specs:
pv = pkg_resources.parse_version(v)
if op == _opeqop[cop0]:
specs.append((op[0], v, pv))
specs.append(('==', v, pv))
else:
specs.append((op, v, pv))
# Error if there are opposite specs that conflict with the constraint
# and there are no equal specs that satisfy the constraint:
if [v for (op, v, pv) in specs
if op == _opop[cop0] and _comparef[_opop[cop0]](pv, pcv)
]:
eqspecs = [op+v for (op, v, pv) in specs
if _comparef[cop](pv, pcv)]
if eqspecs:
# OK, we do, use these:
return ','.join(eqspecs)
bad_constraint(constraint, requirement)
# We have a combination of range constraints and eq specs that
# satisfy the requirement.
# Return the constraint + the filtered specs
return ','.join(
op+v
for (op, v) in (
[(cop, cv)] +
[(op, v) for (op, v, pv) in specs if _comparef[cop](pv, pcv)]
)
)
...@@ -2709,30 +2709,9 @@ def test_constrained_requirement(): ...@@ -2709,30 +2709,9 @@ def test_constrained_requirement():
>>> examples = [ >>> examples = [
... # original, constraint, transformed ... # original, constraint, transformed
... ('x', '1', 'x==1'), ... ('x', '1', 'x==1'),
... ('x>1', '2', 'x==2'), ... ('x>1', '2', 'x>1,==2'),
... ('x>3', '2', IncompatibleConstraintError), ... ('x>3', '2', IncompatibleConstraintError),
... ('x>1', '>2', 'x>2'), ... ('x>1', '>2', 'x>1,>2'),
... ('x>1', '> 2', 'x>2'),
... ('x>1', '>=2', 'x>=2'),
... ('x<1', '>2', IncompatibleConstraintError),
... ('x<=1', '>=1', 'x>=1,<1,==1'),
... ('x<3', '>1', 'x>1,<3'),
... ('x==2', '>1', 'x==2'),
... ('x==2', '>=2', 'x==2'),
... ('x[y]', '1', 'x[y]==1'),
... ('x[y]>1', '2', 'x[y]==2'),
... ('x<3', '2', 'x==2'),
... ('x<1', '2', IncompatibleConstraintError),
... ('x<3', '<2', 'x<2'),
... ('x<3', '< 2', 'x<2'),
... ('x<3', '<=2', 'x<=2'),
... ('x<3', '<= 2', 'x<=2'),
... ('x>3', '<2', IncompatibleConstraintError),
... ('x>=1', '<=1', 'x<=1,>1,==1'),
... ('x<3', '>1', 'x>1,<3'),
... ('x==2', '<3', 'x==2'),
... ('x==2', '<=2', 'x==2'),
... ('x[y]<3', '2', 'x[y]==2'),
... ] ... ]
>>> from zc.buildout.easy_install import _constrained_requirement >>> from zc.buildout.easy_install import _constrained_requirement
>>> for o, c, e in examples: >>> for o, c, e in examples:
...@@ -2829,13 +2808,14 @@ def want_new_zcrecipeegg(): ...@@ -2829,13 +2808,14 @@ def want_new_zcrecipeegg():
... eggs = demo ... eggs = demo
... ''') ... ''')
>>> print_(system(join('bin', 'buildout')), end='') # doctest: +ELLIPSIS >>> print_(system(join('bin', 'buildout')), end='') # doctest: +ELLIPSIS
The constraint, >=2.0.0a3,... Getting distribution for 'zc.recipe.egg<2dev,>=2.0.0a3'.
While: While:
Installing. Installing.
Getting section egg. Getting section egg.
Initializing section egg. Initializing section egg.
Installing recipe zc.recipe.egg <2dev. Installing recipe zc.recipe.egg <2dev.
Error: Bad constraint >=2.0.0a3 zc.recipe.egg<2dev Getting distribution for 'zc.recipe.egg<2dev,>=2.0.0a3'.
Error: Couldn't find a distribution for 'zc.recipe.egg<2dev,>=2.0.0a3'.
""" """
def macro_inheritance_bug(): def macro_inheritance_bug():
......
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