From 1d37beb78b1b0cb7b2e848c6861f7d035ed781ec Mon Sep 17 00:00:00 2001 From: Andriy Kurilin Date: Fri, 5 Sep 2025 08:55:14 +0200 Subject: [PATCH] Update requirements - Bump min rally to >=5.0.0 - Update base image of docker - Update upper-constraints file - drop pkg_resources usage in the tests Change-Id: If1842d15df0a7e6e2c85b8e538e55e3eefab5485 Signed-off-by: Andriy Kurilin --- .zuul.d/zuul.yaml | 2 - CHANGELOG.rst | 3 +- Dockerfile | 2 +- pyproject.toml | 5 +- requirements.txt | 8 +- test-requirements.txt | 8 +- tests/ci/sync_requirements.py | 51 ++++---- tests/unit/test_workarounds.py | 26 +++-- tox.ini | 4 +- upper-constraints.txt | 208 ++++++++++++++++----------------- 10 files changed, 166 insertions(+), 151 deletions(-) diff --git a/.zuul.d/zuul.yaml b/.zuul.d/zuul.yaml index 7af63c96..6a639385 100644 --- a/.zuul.d/zuul.yaml +++ b/.zuul.d/zuul.yaml @@ -3,7 +3,6 @@ jobs: - rally-tox-cover - rally-tox-pep8 - - rally-tox-py39 - rally-tox-py310 - rally-tox-py311 - rally-tox-py312 @@ -77,7 +76,6 @@ jobs: - rally-tox-cover - rally-tox-pep8 - - rally-tox-py39 - rally-tox-py310 - rally-tox-py311 - rally-tox-py312 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b31f1297..8e734c1a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,7 +27,7 @@ Added Removed ~~~~~~~ -* Support for Python 3.8 is dropped +* Support for Python 3.8 and Python 3.9 is dropped * Removed all support for the retired Murano project * Removed all support for the retired Sahara project * Removed all support for the retired Senlin project @@ -39,6 +39,7 @@ Changed * Implements pep-517 (pyproject.toml) and replaces pbr dependency with setuptools-scm * Zaqar scenarios now use messaging v2 API, instead of deprecated v1 API. +* Bump minimal required version to Rally 5.0.0. Switch docker image to use it. Fixed ~~~~~ diff --git a/Dockerfile b/Dockerfile index 82a36152..6b943b49 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM xrally/xrally:4.1.0 +FROM xrally/xrally:5.0.0 # "rally" user (which is selected by-default) is owner of "/rally" directory, # so there is no need to call chown or switch the user diff --git a/pyproject.toml b/pyproject.toml index 3af0e27e..1f6619af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,13 +16,12 @@ classifiers = [ "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", ] dynamic = ["version", "dependencies"] -requires-python = ">=3.9" +requires-python = ">=3.10" [project.urls] Homepage = "https://docs.openstack.org/rally/latest/" @@ -53,4 +52,4 @@ path = "rally_openstack" options = "rally_openstack.common.cfg.opts:list_opts" [project.entry-points."oslo.config.opts"] -rally_openstack = "rally_openstack.common.cfg.opts:list_opts" \ No newline at end of file +rally_openstack = "rally_openstack.common.cfg.opts:list_opts" diff --git a/requirements.txt b/requirements.txt index ec14d586..6a363bfb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,11 @@ -requests!=2.20.0,!=2.24.0 # Apache-2.0 +requests!=2.20.0,!=2.24.0 # Apache License, Version 2.0 -rally>=4.1.0 # Apache License, Version 2.0 -setuptools_scm +rally>=5.0.0 # Apache License, Version 2.0 +setuptools_scm # MIT # OpenStack related gnocchiclient # Apache Software License -keystoneauth1 # Apache Software License +keystoneauth1 # Apache License, Version 2.0 kubernetes # Apache License Version 2.0 os-faults>=0.2.0 # Apache Software License osprofiler # Apache Software License diff --git a/test-requirements.txt b/test-requirements.txt index 3b31155d..0f1fa8d7 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -3,7 +3,7 @@ # process, which may cause wedges in the gate later. hacking>=3.0 # Apache Software License -fixtures # Apache Software License/BSD License +fixtures # Apache-2.0 or BSD pytest # MIT # py.test plugin for measuring coverage. @@ -11,11 +11,11 @@ pytest-cov # MIT # py.test plugin for generating HTML reports pytest-html # MIT # py.test xdist plugin for distributed testing and loop-on-failing modes -pytest-xdist # MIT +pytest-xdist -coverage!=4.4 # Apache-2.0 +coverage!=4.4 # Apache License, Version 2.0 ddt # MIT # docs -docutils # BSD License/GNU General Public License (GPL)/Python Software Foundation License +docutils # BSD License/GNU General Public License (GPL) Pygments # BSD-2-Clause diff --git a/tests/ci/sync_requirements.py b/tests/ci/sync_requirements.py index 82858753..993b55f6 100644 --- a/tests/ci/sync_requirements.py +++ b/tests/ci/sync_requirements.py @@ -18,13 +18,12 @@ Synchronizes, formats and prepares requirements to release(obtains and adds maximum allowed version). """ -import collections +import importlib.metadata import logging import re import sys import textwrap -import pkg_resources import requests @@ -69,12 +68,15 @@ _PYPI_CACHE = {} class PYPIPackage(object): # NOTE(andreykurilin): one license can have different labels. Let's use # unified variant. - LICENSE_MAP = {"MIT license": "MIT", - "MIT License": "MIT", - "BSD License": "BSD", - "Apache 2.0": "Apache License, Version 2.0"} + LICENSE_MAP = { + "MIT license": "MIT", + "MIT License": "MIT", + "BSD License": "BSD", + "Apache-2.0": "Apache License, Version 2.0", + "Apache 2.0": "Apache License, Version 2.0", + } - def __init__(self, package_name): + def __init__(self, package_name: str) -> None: self.package_name = package_name self._pypi_info = None self._pypi_license = None @@ -106,8 +108,10 @@ class PYPIPackage(object): def pypi_license(self): if self._pypi_license is None: if self.pypi_info["info"]["license"]: - self._pypi_license = self.pypi_info["info"]["license"] - else: + if "\n" not in self.pypi_info["info"]["license"]: + self._pypi_license = self.pypi_info["info"]["license"] + + if not self._pypi_license: # try to parse classifiers prefix = "License :: OSI Approved :: " classifiers = [c[len(prefix):] @@ -116,8 +120,6 @@ class PYPIPackage(object): self._pypi_license = "/".join(classifiers) self._license = self.LICENSE_MAP.get(self._pypi_license, self._pypi_license) - if self._pypi_license == "UNKNOWN": - self._pypi_license = None return self._license def __eq__(self, other): @@ -262,7 +264,11 @@ class UpperConstraint(PYPIPackage): return self.version -def parse_data(raw_data, include_comments=True, dependency_cls=Requirement): +def parse_data( + raw_data: str, + include_comments: bool = True, + dependency_cls: type[PYPIPackage] = Requirement +): # first elem is None to simplify checks of last elem in requirements requirements = [None] for line in raw_data.split("\n"): @@ -299,9 +305,11 @@ def parse_data(raw_data, include_comments=True, dependency_cls=Requirement): requirements.pop(i) else: break - return collections.OrderedDict( + return dict( (v if isinstance(v, Comment) else v.package_name, v) - for v in requirements if v) + for v in requirements + if v + ) def _fetch_from_gr(filename): @@ -357,14 +365,17 @@ def update_upper_constraints(): # NOTE(andreykurilin): global OpenStack upper-constraints file includes # comments which can be unrelated to Rally project, so let's just ignore # them. - global_uc = parse_data(raw_g_uc, - include_comments=False, - dependency_cls=UpperConstraint) + global_uc: dict[str, UpperConstraint] = parse_data( + raw_g_uc, + include_comments=False, + dependency_cls=UpperConstraint + ) - our_uc = [UpperConstraint(package_name=p.project_name, version=p.version) - for p in pkg_resources.working_set + our_uc = [UpperConstraint(package_name=p.metadata["Name"], + version=p.version) + for p in importlib.metadata.distributions() # do not include the current package at u-c - if p.project_name != "rally-openstack"] + if p.metadata["Name"] not in ("rally-openstack", "pip")] for package in our_uc: if package.package_name in global_uc: diff --git a/tests/unit/test_workarounds.py b/tests/unit/test_workarounds.py index c0094de8..108e613c 100644 --- a/tests/unit/test_workarounds.py +++ b/tests/unit/test_workarounds.py @@ -20,7 +20,7 @@ This module should contain historical notes and checks to do not forget remove these workaround. """ -import pkg_resources +import importlib.metadata from tests.unit import test @@ -30,18 +30,22 @@ class WorkaroundTestCase(test.TestCase): WORKAROUNDS = [] def get_min_required_version(self): - package = pkg_resources.get_distribution("rally-openstack") - requirement = [p for p in package.requires() if p.name == "rally"][0] + dist = importlib.metadata.distribution("rally-openstack") - for statement, version in requirement.specs: - version = [int(i) for i in version.split(".")] - if statement == ">=": - return version - elif statement == ">": + for p in dist.requires or []: + if not p.startswith("rally>"): + continue + version_str = p.split(">", 1)[1] + ge = version_str.startswith("=") + if ge: + version_str = version_str[1:] + version = [int(i) for i in version_str.split(".")] + if ge: version[-1] += 1 - return version - self.skipTest("Failed to get a minimum required version of Rally " - "framework.") + return version + + self.fail("Failed to get a minimum required version of Rally " + "framework.") def test_rally_version(self): rally_version = self.get_min_required_version() diff --git a/tox.ini b/tox.ini index f43d9dde..1c3b29f4 100644 --- a/tox.ini +++ b/tox.ini @@ -81,11 +81,12 @@ commands = oslo-config-generator --config-file etc/rally/rally-config-generator.conf [testenv:requirements] +skip_install = true deps = # do not use upper-constraints file requests[security] -r{toxinidir}/requirements.txt -commands = python {toxinidir}/tests/ci/sync_requirements.py {posargs} +commands = python3 {toxinidir}/tests/ci/sync_requirements.py {posargs} [flake8] # H105 Don't use author tags @@ -159,3 +160,4 @@ filterwarnings = ignore:Deprecated call to `pkg_resources.declare_namespace*:DeprecationWarning: # python 3.12 ignore:Attribute s is deprecated and will be removed in Python 3.14; use value instead:DeprecationWarning: + ignore:eventletutils module is deprecated and will be removed\.:DeprecationWarning: diff --git a/upper-constraints.txt b/upper-constraints.txt index 7c3a3214..857327ae 100644 --- a/upper-constraints.txt +++ b/upper-constraints.txt @@ -1,119 +1,119 @@ -alembic===1.13.1 -appdirs===1.4.4 -attrs===23.2.0 +alembic===1.16.4 +attrs===25.3.0 autopage===0.5.2 -Babel===2.14.0 -bcrypt===4.1.2 -cachetools===5.3.3 -certifi===2024.2.2 -cffi===1.16.0 -charset-normalizer===3.3.2 -click===8.1.7 -cliff===4.6.0 -cmd2===2.4.3 -cryptography===42.0.5 +bcrypt===4.0.1 +cachetools===5.5.2 +certifi===2025.8.3 +cffi===1.17.1 +charset-normalizer===3.4.2 +click===8.2.2 +cliff===4.10.0 +cmd2===2.7.0 +cryptography===43.0.3 debtcollector===3.0.0 -decorator===5.1.1 -distlib===0.3.8 -dogpile.cache===1.3.2 +decorator===5.2.1 +distlib===0.4.0 +dogpile.cache===1.4.0 +durationpy===0.10 fasteners===0.19 -filelock===3.13.3 -futurist===3.0.0 -gnocchiclient===7.0.8 -google-auth===2.29.0 -idna===3.6 +filelock===3.18.0 +futurist===3.2.1 +gnocchiclient===7.2.0 +google-auth===2.40.3 +greenlet===3.2.3 +idna===3.10 +invoke===2.2.0 iso8601===2.1.0 -jinja2===3.1.4 +Jinja2===3.1.6 jmespath===1.0.1 jsonpatch===1.33 -jsonpointer===2.4 -jsonschema===4.19.2 -jsonschema-specifications===2023.12.1 -keystoneauth1===5.6.0 -kubernetes===29.0.0 -Mako===1.3.2 -MarkupSafe===2.1.5 -msgpack===1.0.8 -netaddr===0.10.1 -netifaces===0.11.0 -oauthlib===3.2.2 -openstacksdk===3.1.0 -os-client-config===2.1.0 -os-faults===0.2.7 -os-service-types===1.7.0 -osc-lib===3.0.1 -oslo.concurrency===6.0.0 -oslo.config===9.4.0 -oslo.context===5.5.0 -oslo.db===15.0.0 -oslo.i18n===6.3.0 -oslo.log===5.5.1 -oslo.serialization===5.4.0 -oslo.utils===7.1.0 -osprofiler===4.1.0 -packaging===24.0 -paramiko===3.4.0 -pbr===6.0.0 -pip===24.0 -platformdirs===4.2.0 -ply===3.11 -prettytable===3.10.0 +jsonpointer===3.0.0 +jsonschema===4.25.0 +jsonschema-specifications===2025.4.1 +keystoneauth1===5.12.0 +kubernetes===33.1.0 +Mako===1.3.10 +markdown-it-py===3.0.0 +MarkupSafe===3.0.2 +mdurl===0.1.2 +msgpack===1.1.1 +netaddr===1.3.0 +oauthlib===3.3.1 +openstacksdk===4.6.0 +os-client-config===2.3.0 +os-faults===0.3.0 +os-service-types===1.8.0 +osc-lib===4.1.0 +oslo.concurrency===7.2.0 +oslo.config===10.0.0 +oslo.context===6.1.0 +oslo.db===17.4.0 +oslo.i18n===6.6.0 +oslo.log===7.2.1 +oslo.serialization===5.8.0 +oslo.utils===9.1.0 +osprofiler===4.3.0 +packaging===25.0 +paramiko===3.5.1 +pbr===7.0.1 +platformdirs===4.3.8 +prettytable===3.16.0 +psutil===7.0.0 pyasn1===0.6.0 -pyasn1-modules===0.4.0 +pyasn1_modules===0.4.1 pycparser===2.22 -pyghmi===1.5.68 +pyghmi===1.6.2 +Pygments===2.19.2 PyNaCl===1.5.0 -pyOpenSSL===24.1.0 -pyparsing===3.1.2 -pyperclip===1.8.2 -python-barbicanclient===5.7.0 -python-cinderclient===9.5.0 +pyOpenSSL===24.2.1 +pyparsing===3.2.3 +pyperclip===1.9.0 +python-barbicanclient===7.2.0 +python-cinderclient===9.8.0 python-dateutil===2.9.0.post0 -python-designateclient===6.0.1 -python-glanceclient===4.5.0 -python-heatclient===3.5.0 -python-ironicclient===5.6.0 -python-keystoneclient===5.4.0 -python-magnumclient===4.4.0 -python-manilaclient===4.8.0 -python-mistralclient===5.2.0 -python-monascaclient===2.8.0 -python-neutronclient===11.2.0 -python-novaclient===18.6.0 -python-octaviaclient===3.7.0 -python-openstackclient===6.6.0 +python-designateclient===6.3.0 +python-glanceclient===4.9.0 +python-heatclient===4.3.0 +python-ironicclient===5.13.0 +python-keystoneclient===5.7.0 +python-magnumclient===4.9.0 +python-manilaclient===5.6.0 +python-mistralclient===6.0.0 +python-neutronclient===11.6.0 +python-novaclient===18.11.0 +python-octaviaclient===3.12.0 +python-openstackclient===8.1.0 python-subunit===1.4.4 -python-swiftclient===4.5.0 -python-troveclient===8.4.0 -python-watcherclient===4.4.0 -python-zaqarclient===2.7.0 -PyYAML===6.0.1 -rally===4.1.0 -referencing===0.34.0 -requests===2.31.0 -requests-oauthlib===1.3.1 +python-swiftclient===4.8.0 +python-troveclient===8.9.0 +python-watcherclient===4.9.0 +python-zaqarclient===4.0.0 +PyYAML===6.0.2 +rally===5.0.0 +referencing===0.36.2 +requests===2.32.4 +requests-oauthlib===2.0.0 requestsexceptions===1.4.0 rfc3986===2.0.0 -rpds-py===0.18.0 -rsa===4.9 -semantic-version===2.10.0 -setuptools===69.2.0 -simplejson===3.19.2 -six===1.16.0 -SQLAlchemy===2.0.29 -stevedore===5.2.0 -testresources===2.0.1 +rich===14.1.0 +rich-argparse===1.7.1 +rpds-py===0.26.0 +rsa===4.9.1 +setuptools===80.9.0 +setuptools-scm===9.2.0 +six===1.17.0 +SQLAlchemy===2.0.42 +stevedore===5.5.0 +testresources===2.0.2 testscenarios===0.5.0 -testtools===2.7.1 -typing-extensions===4.11.0 -tzdata===2024.1 -ujson===5.9.0 -urllib3===1.26.18 -virtualenv===20.25.1 -warlock===2.0.1 +testtools===2.7.2 +typing_extensions===4.14.1 +tzdata===2025.2 +ujson===5.10.0 +urllib3===1.26.20 +virtualenv===20.32.0 +warlock===2.1.0 wcwidth===0.2.13 -WebOb===1.8.7 -websocket-client===1.7.0 -wheel===0.43.0 -wrapt===1.16.0 -yaql===3.0.0 +WebOb===1.8.9 +websocket-client===1.8.0 +wrapt===1.17.2