Commit 2dbcc13a authored by Godefroid Chapelle's avatar Godefroid Chapelle

Problem: requirements parse errors with new setuptools

Solution: use packaging APIs
parent ebe73268
...@@ -18,12 +18,14 @@ It doesn't install scripts. It uses setuptools and requires it to be ...@@ -18,12 +18,14 @@ It doesn't install scripts. It uses setuptools and requires it to be
installed. installed.
""" """
import copy
import distutils.errors import distutils.errors
import errno import errno
import glob import glob
import logging import logging
import os import os
import pkg_resources import pkg_resources
from pkg_resources import packaging
import py_compile import py_compile
import re import re
import setuptools.archive_util import setuptools.archive_util
...@@ -1618,30 +1620,25 @@ def redo_pyc(egg): ...@@ -1618,30 +1620,25 @@ def redo_pyc(egg):
call_subprocess(args) call_subprocess(args)
def _constrained_requirement(constraint, requirement): def _constrained_requirement(constraint, requirement):
assert isinstance(requirement, pkg_resources.Requirement)
if constraint[0] not in '<>': if constraint[0] not in '<>':
if constraint.startswith('='): if constraint.startswith('='):
assert constraint.startswith('==') assert constraint.startswith('==')
constraint = constraint[2:] version = constraint[2:]
if constraint not in requirement: else:
version = constraint
constraint = '==' + constraint
if version not in requirement:
msg = ("The requirement (%r) is not allowed by your [versions] " msg = ("The requirement (%r) is not allowed by your [versions] "
"constraint (%s)" % (str(requirement), constraint)) "constraint (%s)" % (str(requirement), version))
raise IncompatibleConstraintError(msg) raise IncompatibleConstraintError(msg)
specifier = packaging.specifiers.SpecifierSet(constraint)
# Sigh, copied from Requirement.__str__
extras = ','.join(requirement.extras)
if extras:
extras = '[%s]' % extras
return pkg_resources.Requirement.parse(
"%s%s==%s" % (requirement.project_name, extras, constraint))
if requirement.specs:
return pkg_resources.Requirement.parse(
str(requirement) + ',' + constraint
)
else: else:
return pkg_resources.Requirement.parse( specifier = requirement.specifier & constraint
str(requirement) + ' ' + constraint constrained = copy.deepcopy(requirement)
) constrained.specifier = specifier
return pkg_resources.Requirement.parse(str(constrained))
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.
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2020 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import doctest
import re
from zope.testing import renormalizing
import zc.buildout.testing
from zc.buildout.tests import easy_install_SetUp
from zc.buildout.tests import normalize_bang
def install_extras_with_greater_than_constrains():
"""
There was a bug that caused extras in requirements to be lost.
>>> working = tmpdir('working')
>>> cd(working)
>>> mkdir('dependency')
>>> cd('dependency')
>>> with open('setup.py', 'w') as f:
... _ = f.write('''
... from setuptools import setup
... setup(name='dependency', version='1.0',
... url='x', author='x', author_email='x',
... py_modules=['t'])
... ''')
>>> open('README', 'w').close()
>>> open('t.py', 'w').close()
>>> sdist('.', sample_eggs)
>>> cd(working)
>>> mkdir('extras')
>>> cd('extras')
>>> with open('setup.py', 'w') as f:
... _ = f.write('''
... from setuptools import setup
... setup(name='extraversiondemo', version='1.0',
... url='x', author='x', author_email='x',
... extras_require=dict(foo=['dependency']), py_modules=['t'])
... ''')
>>> open('README', 'w').close()
>>> open('t.py', 'w').close()
>>> sdist('.', sample_eggs)
>>> mkdir('dest')
>>> ws = zc.buildout.easy_install.install(
... ['extraversiondemo[foo]'], 'dest', links=[sample_eggs],
... versions = dict(extraversiondemo='1.0', dependency='>0.9')
... )
>>> sorted(dist.key for dist in ws)
['dependency', 'extraversiondemo']
"""
def test_suite():
return doctest.DocTestSuite(
setUp=easy_install_SetUp,
tearDown=zc.buildout.testing.buildoutTearDown,
checker=renormalizing.RENormalizing([
zc.buildout.testing.normalize_path,
zc.buildout.testing.normalize_endings,
zc.buildout.testing.normalize_script,
zc.buildout.testing.normalize_egg_py,
zc.buildout.testing.normalize___pycache__,
zc.buildout.testing.not_found,
zc.buildout.testing.normalize_exception_type_for_python_2_and_3,
zc.buildout.testing.adding_find_link,
zc.buildout.testing.python27_warning,
zc.buildout.testing.python27_warning_2,
normalize_bang,
(re.compile(r'^(\w+\.)*(Missing\w+: )'), '\2'),
(re.compile(r"buildout: Running \S*setup.py"),
'buildout: Running setup.py'),
(re.compile(r'pip-\S+-'),
'pip.egg'),
(re.compile(r'setuptools-\S+-'),
'setuptools.egg'),
(re.compile(r'zc.buildout-\S+-'),
'zc.buildout.egg'),
(re.compile(r'pip = \S+'), 'pip = 20.0.0'),
(re.compile(r'setuptools = \S+'), 'setuptools = 0.7.99'),
(re.compile(r'File "\S+one.py"'),
'File "one.py"'),
(re.compile(r'We have a develop egg: (\S+) (\S+)'),
r'We have a develop egg: \1 V'),
(re.compile(r'Picked: setuptools = \S+'),
'Picked: setuptools = V'),
(re.compile('[-d] pip'), '- pip'),
(re.compile('[-d] setuptools'), '- setuptools'),
(re.compile(r'\\[\\]?'), '/'),
(re.compile(
'-q develop -mxN -d "/sample-buildout/develop-eggs'),
'-q develop -mxN -d /sample-buildout/develop-eggs'
),
(re.compile(r'^[*]...'), '...'),
# for
# bug_92891
# bootstrap_crashes_with_egg_recipe_in_buildout_section
(re.compile(r"Unused options for buildout: 'eggs' 'scripts'\."),
"Unused options for buildout: 'scripts' 'eggs'."),
# Python 3.4 changed the wording of NameErrors
(re.compile('NameError: global name'), 'NameError: name'),
# fix for test_distutils_scripts_using_import_are_properly_parsed
# and test_distutils_scripts_using_from_are_properly_parsed
# win32 apparently adds a " around sys.executable
(re.compile('#!"python"'), '#!python'),
]),
)
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