From 751bd3dfedd3a974b79c53393702578351bb6787 Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Thu, 11 Jul 2024 09:15:06 +0200 Subject: [PATCH] Drop support for Python 3.7. (#153) * Update Python version support. * ensure environment universal2 exists * hand-install dependencies on macOS, similar to Zope tests --------- Co-authored-by: Jens Vagelpohl --- .github/workflows/tests.yml | 25 ++++++++++---------- .meta.toml | 20 +++++++++++++++- CHANGES.rst | 2 +- setup.py | 3 +-- src/Products/ZCTextIndex/WidCode.py | 4 ++-- src/Products/ZCatalog/plan.py | 36 ++++++++++++++--------------- tox.ini | 19 ++++++++++++++- 7 files changed, 70 insertions(+), 39 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 79f16583..7aaeeb6b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,27 +17,22 @@ jobs: fail-fast: false matrix: os: - - ["ubuntu", "ubuntu-20.04"] - - ["macos", "macos-11"] + - ["ubuntu", "ubuntu-latest"] + - ["macos", "macos-latest"] config: # [Python version, tox env] - - ["3.9", "release-check"] - - ["3.9", "lint"] - - ["3.7", "py37"] + - ["3.11", "release-check"] + - ["3.11", "lint"] - ["3.8", "py38"] - ["3.9", "py39"] - ["3.10", "py310"] - ["3.11", "py311"] - ["3.12", "py312"] - - ["3.9", "coverage"] + - ["3.11", "coverage"] exclude: - - { os: ["macos", "macos-11"], config: ["3.9", "release-check"] } - - { os: ["macos", "macos-11"], config: ["3.9", "lint"] } - - { os: ["macos", "macos-11"], config: ["3.9", "coverage"] } - # macOS/Python 3.11+ is set up for universal2 architecture - # which causes build and package selection issues. - - { os: ["macos", "macos-11"], config: ["3.11", "py311"] } - - { os: ["macos", "macos-11"], config: ["3.12", "py312"] } + - { os: ["macos", "macos-latest"], config: ["3.11", "release-check"] } + - { os: ["macos", "macos-latest"], config: ["3.11", "lint"] } + - { os: ["macos", "macos-latest"], config: ["3.11", "coverage"] } runs-on: ${{ matrix.os[1] }} if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name @@ -61,7 +56,11 @@ jobs: python -m pip install --upgrade pip pip install tox - name: Test + if: ${{ !startsWith(runner.os, 'Mac') }} run: tox -e ${{ matrix.config[1] }} + - name: Test (macOS) + if: ${{ startsWith(runner.os, 'Mac') }} + run: tox -e ${{ matrix.config[1] }}-universal2 - name: Coverage if: matrix.config[1] == 'coverage' run: | diff --git a/.meta.toml b/.meta.toml index ed67fb9e..220b6118 100644 --- a/.meta.toml +++ b/.meta.toml @@ -2,7 +2,7 @@ # https://github.com/zopefoundation/meta/tree/master/config/zope-product [meta] template = "zope-product" -commit-id = "1351c95d" +commit-id = "c412f00f" [python] with-pypy = false @@ -10,6 +10,7 @@ with-sphinx-doctests = false with-windows = false with-future-python = false with-macos = true +with-docs = false [coverage] fail-under = 85 @@ -25,3 +26,20 @@ additional-rules = [ [tox] use-flake8 = true +testenv-deps = [ + "cffi >= 1.17.0rc1", + "# The universal2 environment is for Python on macOS built with", + "# universal2 mode instead of architecture-specific. These dependencies", + "# must be installed separately, zc.buildout is incompatible with the", + "# universal2 mode and cannot install them itself.", + "universal2: zope.interface", + "universal2: zope.security", + "universal2: zope.container", + "universal2: Persistence", + "universal2: Acquisition", + "universal2: AccessControl", + "universal2: zodbpickle", + "universal2: charset_normalizer", + "universal2: MarkupSafe", + "universal2: zope.testrunner", + ] diff --git a/CHANGES.rst b/CHANGES.rst index e7a31c39..79329fe2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,7 @@ Changelog 7.2 (unreleased) ---------------- -- Nothing changed yet. +- Drop support for Python 3.7. 7.1 (2024-03-21) diff --git a/setup.py b/setup.py index 9967f502..1eaa4dc9 100644 --- a/setup.py +++ b/setup.py @@ -44,7 +44,6 @@ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -54,7 +53,7 @@ "Topic :: Internet :: WWW/HTTP :: Indexing/Search", ], keywords='Zope catalog index search data', - python_requires='>=3.7', + python_requires='>=3.8', install_requires=[ 'setuptools', 'AccessControl >= 4.0a4', diff --git a/src/Products/ZCTextIndex/WidCode.py b/src/Products/ZCTextIndex/WidCode.py index 9efa8817..bf77cc71 100644 --- a/src/Products/ZCTextIndex/WidCode.py +++ b/src/Products/ZCTextIndex/WidCode.py @@ -75,7 +75,7 @@ def _encode(w): b, c = divmod(w, 0x80) a, b = divmod(b, 0x80) s = chr(b) + chr(c) - if a < 0x80: # no more than 21 data bits + if a < 0x80: # no more than 21 data bits return chr(a + 0x80) + s a, b = divmod(a, 0x80) assert a < 0x80, (w, a, b, s) # else more than 28 data bits @@ -86,7 +86,7 @@ def _encode(w): def decode(code): - # Handle bytes that were not properly decoded during Python 3 conversion + # Handle bytes that were not properly decoded during Python-3-conversion if isinstance(code, bytes): code = code.decode('latin1') # Decode a string into a list of wids. diff --git a/src/Products/ZCatalog/plan.py b/src/Products/ZCatalog/plan.py index 83b56996..8c4e0b62 100644 --- a/src/Products/ZCatalog/plan.py +++ b/src/Products/ZCatalog/plan.py @@ -104,7 +104,7 @@ def load_default(cls): try: pmap = resolve(location) cls.load_pmap(location, pmap) - except ImportError: + except ModuleNotFoundError: logger.warning(f'could not load priority map from {location}') @classmethod @@ -121,8 +121,7 @@ def load_from_path(cls, path): @classmethod def load_pmap(cls, location, pmap): - logger.info('loaded priority %d map(s) from %s', - len(pmap), location) + logger.info('loaded priority %d map(s) from %s', len(pmap), location) # Convert the simple benchmark tuples to namedtuples new_plan = {} for cid, plan in pmap.items(): @@ -251,8 +250,7 @@ def make_key(self, query): key = [name for name in key if name not in notkeys] key.extend([(name, "not") for name in notkeys]) # Workaround: Python only sorts on identical types. - tuple_keys = set(key) - { - x for x in key if not isinstance(x, tuple)} + tuple_keys = set(key) - {x for x in key if not isinstance(x, tuple)} str_keys = set(key) - tuple_keys return tuple(sorted(str_keys)) + tuple(sorted(tuple_keys)) @@ -264,9 +262,9 @@ def plan(self): # sort indexes on (limited result index, mean search time) # skip internal ('#') bookkeeping records - ranking = sorted( - [((value.limit, value.duration), name) - for name, value in benchmark.items() if '#' not in name]) + ranking = sorted([((value.limit, value.duration), name) + for name, value in benchmark.items() + if '#' not in name]) return [r[1] for r in ranking] def start(self): @@ -281,8 +279,7 @@ def stop_split(self, name, result=None, limit=False): start_time, stop_time = self.interim.get(name, Duration(None, None)) self.interim[name] = Duration(start_time, current) dt = current - start_time - self.res.append(IndexMeasurement( - name=name, duration=dt, limit=limit)) + self.res.append(IndexMeasurement(name=name, duration=dt, limit=limit)) if name.startswith('sort_on'): # sort_on isn't an index. We only do time reporting on it @@ -291,8 +288,7 @@ def stop_split(self, name, result=None, limit=False): # remember index's hits, search time and calls benchmark = self.benchmark if name not in benchmark: - benchmark[name] = Benchmark(duration=dt, - hits=1, limit=limit) + benchmark[name] = Benchmark(duration=dt, hits=1, limit=limit) else: duration, hits, limit = benchmark[name] duration = ((duration * hits) + dt) / float(hits + 1) @@ -316,8 +312,7 @@ def stop(self): if key in self.catalog.indexes: index = self.catalog.indexes[key] self.benchmark[key] = Benchmark( - 0, 0, ILimitedResultIndex.providedBy(index) - ) + 0, 0, ILimitedResultIndex.providedBy(index)) else: self.benchmark[key] = Benchmark(0, 0, False) PriorityMap.set_entry(self.cid, self.key, self.benchmark) @@ -354,11 +349,14 @@ def report(self): 'query': key, 'counter': report.hits, 'duration': report.duration * 1000, - 'last': {'duration': last.duration * 1000, - 'details': [dict(id=d.name, - duration=d.duration * 1000) - for d in last.details], - }, + 'last': { + 'duration': + last.duration * 1000, + 'details': [ + dict(id=d.name, duration=d.duration * 1000) + for d in last.details + ], + }, } rval.append(info) diff --git a/tox.ini b/tox.ini index 5f542663..a533a013 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,6 @@ minversion = 3.18 envlist = release-check lint - py37 py38 py39 py310 @@ -16,8 +15,24 @@ envlist = [testenv] skip_install = true deps = + setuptools < 69 zc.buildout >= 3.0.1 wheel > 0.37 + cffi >= 1.17.0rc1 + # The universal2 environment is for Python on macOS built with + # universal2 mode instead of architecture-specific. These dependencies + # must be installed separately, zc.buildout is incompatible with the + # universal2 mode and cannot install them itself. + universal2: zope.interface + universal2: zope.security + universal2: zope.container + universal2: Persistence + universal2: Acquisition + universal2: AccessControl + universal2: zodbpickle + universal2: charset_normalizer + universal2: MarkupSafe + universal2: zope.testrunner setenv = py312: VIRTUALENV_PIP=23.1.2 py312: PIP_REQUIRE_VIRTUALENV=0 @@ -25,6 +40,7 @@ commands_pre = {envbindir}/buildout -nc {toxinidir}/buildout.cfg buildout:directory={envdir} buildout:develop={toxinidir} install test commands = {envbindir}/test {posargs:-cv} + [testenv:release-check] description = ensure that the distribution is ready to release basepython = python3 @@ -88,6 +104,7 @@ source = Products.ZCatalog [coverage:report] precision = 2 +ignore_errors = True exclude_lines = pragma: no cover pragma: nocover