add build-lower-constraints command

Add a command to merge lower constraints lists together, as a
precursor to removing the global lower-constraints.txt list in this
repository.

Change-Id: Ia238607b9feb292842971d0fc161ae6294150e1f
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
Doug Hellmann 2018-06-29 15:34:56 -04:00
parent 383a1f86bf
commit 9fa26daf57
4 changed files with 150 additions and 0 deletions

View File

@ -51,6 +51,26 @@ are normally constrained::
edit-constraints oslo.db "-e file://opt/stack/oslo.db#egg=oslo.db"
build-lower-constraints
-----------------------
Combine multiple lower-constraints.txt files to produce a list of the
highest version of each package mentioned in the files. This can be
used to produce the "highest minimum" for a global lower constraints
list (a.k.a., the "TJ Maxx").
To use the script, run::
$ tox -e venv -- build-lower-constraints input1.txt input2.txt
Where the input files are lower-constraints.txt or requirements.txt
files from one or more projects.
If the inputs are requirements files, a lower constraints list for the
requirements is produced. If the inputs are lower-constraints.txt, the
output includes the highest version of each package referenced in the
files.
Proposing changes
=================

View File

@ -0,0 +1,72 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Merge multiple lower-constraints.txt files to find the highest values.
"""
import argparse
import collections
from openstack_requirements import requirement
import packaging.specifiers
import packaging.version
def read_requirements_file(filename):
with open(filename, 'rt') as f:
body = f.read()
return requirement.parse(body)
def get_requirements_version(req):
"""Find the version for a requirement.
Use the version attached to >=, ==, or ===, depending on the type
of input requirement.
"""
for specifier in packaging.specifiers.SpecifierSet(req.specifiers):
if '>=' in specifier.operator or '==' in specifier.operator:
return packaging.version.parse(specifier.version)
raise ValueError('could not find version for {}'.format(req))
def merge_constraints_sets(constraints_sets):
"Generator of Requirements with the maximum version for each constraint."
all_constraints = collections.defaultdict(list)
for constraints_set in constraints_sets:
for constraint_name, constraint in constraints_set.items():
all_constraints[constraint_name].extend(constraint)
for constraint_name, constraints in sorted(all_constraints.items()):
val = max((c[0] for c in constraints), key=get_requirements_version)
yield val.to_line()
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'lower_constraints',
nargs='+',
help='lower-constraints.txt files',
)
args = parser.parse_args()
constraints_sets = [
read_requirements_file(filename)
for filename in args.lower_constraints
]
merged = list(merge_constraints_sets(constraints_sets))
print(''.join(merged))

View File

@ -0,0 +1,57 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import testtools
from openstack_requirements.cmds import build_lower_constraints
from openstack_requirements import requirement
class BuildLowerConstraintsTest(testtools.TestCase):
def test_one_input_file(self):
inputs = [
requirement.parse('package==1.2.3'),
]
expected = [
'package==1.2.3\n',
]
self.assertEqual(
expected,
list(build_lower_constraints.merge_constraints_sets(inputs))
)
def test_two_input_file_same(self):
inputs = [
requirement.parse('package==1.2.3'),
requirement.parse('package==1.2.3'),
]
expected = [
'package==1.2.3\n',
]
self.assertEqual(
expected,
list(build_lower_constraints.merge_constraints_sets(inputs))
)
def test_two_input_file_differ(self):
inputs = [
requirement.parse('package==1.2.3'),
requirement.parse('package==4.5.6'),
]
expected = [
'package==4.5.6\n',
]
self.assertEqual(
expected,
list(build_lower_constraints.merge_constraints_sets(inputs))
)

View File

@ -41,3 +41,4 @@ console_scripts =
normalize-requirements = openstack_requirements.cmds.normalize_requirements:main
check-python2-support = openstack_requirements.cmds.check_py2:main
check-constraints = openstack_requirements.cmds.check_exists:main
build-lower-constraints = openstack_requirements.cmds.build_lower_constraints:main