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.
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 --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.
'''
......@@ -59,7 +59,8 @@ parser.add_option("-f", "--find-links",
parser.add_option("--allow-site-packages",
action="store_true", default=False,
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()
......@@ -80,10 +81,10 @@ exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
if not options.allow_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
import site
# inside a virtualenv, there is no 'getsitepackages'.
# inside a virtualenv, there is no 'getsitepackages'.
# We can't remove these reliably
if hasattr(site, 'getsitepackages'):
for sitepackage_path in site.getsitepackages():
......@@ -133,10 +134,15 @@ if version is None and not options.accept_buildout_test_releases:
_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
try:
return not parsed_version.is_prerelease
except AttributeError:
# 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(
search_path=[setuptools_path])
if find_links:
......
......@@ -12,7 +12,7 @@
#
##############################################################################
name = "zc.buildout"
version = "2.2.5"
version = "2.3.dev0"
import os
from setuptools import setup
......@@ -88,7 +88,7 @@ setup(
package_dir = {'': 'src'},
namespace_packages = ['zc'],
install_requires = [
'setuptools>=3.3',
'setuptools>=8.0',
],
include_package_data = True,
entry_points = entry_points,
......
......@@ -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
`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(
... 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
X...Generated script '/sample/bin/buildout'...X
......@@ -106,7 +106,7 @@ Let's make sure the generated `buildout` script uses it::
>>> print_(open(buildout_script).read()) # doctest: +ELLIPSIS
#...
sys.path[0:0] = [
'/sample/eggs/setuptools-5.3...egg',
'/sample/eggs/setuptools-8.0...egg',
'/sample/eggs/zc.buildout-...egg',
]...
......@@ -115,7 +115,7 @@ which happens to exist::
>>> print_('X'); print_(system(
... 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
X...Generated script '/sample/bin/buildout'...X
......@@ -124,6 +124,6 @@ Let's make sure the generated `buildout` script uses it::
>>> print_(open(buildout_script).read()) # doctest: +ELLIPSIS
#...
sys.path[0:0] = [
'/sample/eggs/setuptools-5.3...egg',
'/sample/eggs/setuptools-8.0...egg',
'/sample/eggs/zc.buildout-2.0.0...egg',
]...
......@@ -421,10 +421,10 @@ class Installer:
# Now find the best one:
best = []
bestv = ()
bestv = None
for dist in dists:
distv = dist.parsed_version
if distv > bestv:
if bestv is None or distv > bestv:
best = [dist]
bestv = distv
elif distv == bestv:
......@@ -1350,9 +1350,13 @@ class VersionConflict(zc.buildout.UserError):
result = ["There is a version conflict.",
"We already have: %s" % existing_dist,
]
stated = False
for dist in self.ws:
if req in dist.requires():
result.append("but %s requires %r." % (dist, str(req)))
stated = True
if not stated:
result.append("We require %s" % req)
return '\n'.join(result)
......@@ -1398,10 +1402,7 @@ def _fix_file_links(links):
_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
return not parsed_version.is_prerelease
def redo_pyc(egg):
if not os.path.isdir(egg):
......@@ -1438,13 +1439,22 @@ def redo_pyc(egg):
call_subprocess(args)
def _constrained_requirement(constraint, requirement):
return pkg_resources.Requirement.parse(
"%s[%s]%s" % (
requirement.project_name,
','.join(requirement.extras),
_constrained_requirement_constraint(constraint, requirement)
if constraint[0] not in '<>':
if constraint.startswith('='):
assert constraint.startswith('==')
constraint = constraint[2:]
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):
"""A specified version is incompatible with a given requirement.
......@@ -1456,91 +1466,3 @@ def bad_constraint(constraint, requirement):
logger.error("The constraint, %s, is not consistent with the "
"requirement, %r.", constraint, str(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():
>>> examples = [
... # original, constraint, transformed
... ('x', '1', 'x==1'),
... ('x>1', '2', 'x==2'),
... ('x>1', '2', 'x>1,==2'),
... ('x>3', '2', IncompatibleConstraintError),
... ('x>1', '>2', 'x>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'),
... ('x>1', '>2', 'x>1,>2'),
... ]
>>> from zc.buildout.easy_install import _constrained_requirement
>>> for o, c, e in examples:
......@@ -2829,13 +2808,14 @@ def want_new_zcrecipeegg():
... eggs = demo
... ''')
>>> print_(system(join('bin', 'buildout')), end='') # doctest: +ELLIPSIS
The constraint, >=2.0.0a3,...
Getting distribution for 'zc.recipe.egg<2dev,>=2.0.0a3'.
While:
Installing.
Getting section egg.
Initializing section egg.
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():
......
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