From 3c94ecd3ebb1264d4bf93a4b383b425ba28b8409 Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Sat, 1 Mar 2025 22:59:29 +0100 Subject: [PATCH 1/6] chore: drop pkg_resources usage --- src/plone/restapi/__init__.py | 8 ++++---- src/plone/restapi/services/addons/addons.py | 10 ++++++---- src/plone/restapi/services/querystringsearch/get.py | 9 +++++---- src/plone/restapi/services/system/get.py | 5 ++--- src/plone/restapi/tests/test_content_delete.py | 8 ++++---- src/plone/restapi/tests/test_documentation.py | 4 ++-- src/plone/restapi/tests/test_search.py | 10 +++++----- src/plone/restapi/tests/test_serializer_catalog.py | 10 +++++----- 8 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/plone/restapi/__init__.py b/src/plone/restapi/__init__.py index c2cd6a1bb3..5c71f91a97 100644 --- a/src/plone/restapi/__init__.py +++ b/src/plone/restapi/__init__.py @@ -2,17 +2,17 @@ from AccessControl import allow_module from AccessControl.Permissions import add_user_folders from importlib import import_module +from importlib.metadata import distribution +from importlib.metadata import PackageNotFoundError from plone.restapi.pas import plugin from Products.PluggableAuthService.PluggableAuthService import registerMultiPlugin from zope.i18nmessageid import MessageFactory -import pkg_resources - try: - pkg_resources.get_distribution("plone.app.multilingual") + distribution("plone.app.multilingual") HAS_MULTILINGUAL = True -except pkg_resources.DistributionNotFound: +except PackageNotFoundError: HAS_MULTILINGUAL = False _ = MessageFactory("plone.restapi") diff --git a/src/plone/restapi/services/addons/addons.py b/src/plone/restapi/services/addons/addons.py index 974b2398ee..2e808390da 100644 --- a/src/plone/restapi/services/addons/addons.py +++ b/src/plone/restapi/services/addons/addons.py @@ -1,3 +1,5 @@ +from importlib.metadata import distribution +from importlib.metadata import PackageNotFoundError from plone.memoize import view from plone.restapi.bbb import INonInstallable from Products.CMFCore.utils import getToolByName @@ -7,7 +9,7 @@ from zope.i18n import translate import logging -import pkg_resources +import packaging try: @@ -228,9 +230,9 @@ def get_product_version(self, product_id): That implementation used to fall back to getting the version.txt. """ try: - dist = pkg_resources.get_distribution(product_id) + dist = distribution(product_id) return dist.version - except pkg_resources.DistributionNotFound: + except PackageNotFoundError: if "." in product_id: return "" # For CMFPlacefulWorkflow we need to try Products.CMFPlacefulWorkflow. @@ -247,7 +249,7 @@ def get_latest_upgrade_step(self, profile_id): available = self.ps.listUpgrades(profile_id, True) if available: # could return empty sequence latest = available[-1] - profile_version = max(latest["dest"], key=pkg_resources.parse_version) + profile_version = max(latest["dest"], key=packaging.version.parse) except Exception: pass return profile_version diff --git a/src/plone/restapi/services/querystringsearch/get.py b/src/plone/restapi/services/querystringsearch/get.py index 5e2bfee45d..7cd280f06e 100644 --- a/src/plone/restapi/services/querystringsearch/get.py +++ b/src/plone/restapi/services/querystringsearch/get.py @@ -1,5 +1,4 @@ -from pkg_resources import get_distribution -from pkg_resources import parse_version +from importlib.metadata import distribution from plone.restapi.bbb import IPloneSiteRoot from plone.restapi.deserializer import json_body from plone.restapi.deserializer import parse_int @@ -10,9 +9,11 @@ from zExceptions import BadRequest from zope.component import getMultiAdapter +import packaging -zcatalog_version = get_distribution("Products.ZCatalog").version -if parse_version(zcatalog_version) >= parse_version("5.1"): + +zcatalog_version = distribution("Products.ZCatalog").version +if packaging.version.parse(zcatalog_version) >= packaging.version.parse("5.1"): SUPPORT_NOT_UUID_QUERIES = True else: SUPPORT_NOT_UUID_QUERIES = False diff --git a/src/plone/restapi/services/system/get.py b/src/plone/restapi/services/system/get.py index 5f666a5dea..265ef75970 100644 --- a/src/plone/restapi/services/system/get.py +++ b/src/plone/restapi/services/system/get.py @@ -1,3 +1,4 @@ +from importlib.metadata import distribution from plone.restapi.services import Service @@ -6,10 +7,8 @@ except ImportError: from plone.app.controlpanel.overview import OverviewControlPanel -import pkg_resources - -plone_restapi_version = pkg_resources.require("plone.restapi")[0].version +plone_restapi_version = distribution("plone.restapi").version class SystemGet(Service): diff --git a/src/plone/restapi/tests/test_content_delete.py b/src/plone/restapi/tests/test_content_delete.py index 15844ef59c..98fa419e6d 100644 --- a/src/plone/restapi/tests/test_content_delete.py +++ b/src/plone/restapi/tests/test_content_delete.py @@ -1,5 +1,5 @@ -from pkg_resources import get_distribution -from pkg_resources import parse_version +from importlib.metadata import distribution +from packaging.version import parse as version_parse from plone.app.testing import login from plone.app.testing import setRoles from plone.app.testing import SITE_OWNER_NAME @@ -14,8 +14,8 @@ import unittest -linkintegrity_version = get_distribution("plone.app.linkintegrity").version -if parse_version(linkintegrity_version) >= parse_version("3.0.dev0"): +linkintegrity_version = distribution("plone.app.linkintegrity").version +if version_parse(linkintegrity_version) >= version_parse("3.0.dev0"): NEW_LINKINTEGRITY = True else: NEW_LINKINTEGRITY = False diff --git a/src/plone/restapi/tests/test_documentation.py b/src/plone/restapi/tests/test_documentation.py index c11c41e0cf..46756b3fd7 100644 --- a/src/plone/restapi/tests/test_documentation.py +++ b/src/plone/restapi/tests/test_documentation.py @@ -2,7 +2,7 @@ from datetime import datetime from datetime import timezone import io -from pkg_resources import resource_filename +from importlib.resources import files from plone import api from plone.app.discussion.interfaces import ICommentAddedEvent from plone.app.discussion.interfaces import IConversation @@ -75,7 +75,7 @@ RESPONSE_HEADER_KEYS = ["content-type", "allow", "location"] + TUS_HEADERS -base_path = resource_filename("plone.restapi.tests", "http-examples") +base_path = str(files("plone.restapi").joinpath("tests/http-examples")) UPLOAD_DATA = b"abcdefgh" UPLOAD_MIMETYPE = b"text/plain" diff --git a/src/plone/restapi/tests/test_search.py b/src/plone/restapi/tests/test_search.py index 471340994f..93ba90c50c 100644 --- a/src/plone/restapi/tests/test_search.py +++ b/src/plone/restapi/tests/test_search.py @@ -1,7 +1,6 @@ from datetime import date from DateTime import DateTime -from pkg_resources import get_distribution -from pkg_resources import parse_version +from importlib.metadata import distribution from plone import api from plone.app.discussion.interfaces import IDiscussionSettings from plone.app.testing import SITE_OWNER_NAME @@ -22,13 +21,14 @@ from zope.interface import alsoProvides from zope.interface import noLongerProvides +import packaging import transaction import unittest -HAS_PLONE_6 = parse_version( - get_distribution("Products.CMFPlone").version -) >= parse_version("6.0.0a1") +HAS_PLONE_6 = packaging.version.parse( + distribution("Products.CMFPlone").version +) >= packaging.version.parse("6.0.0a1") class TestSearchFunctional(unittest.TestCase): diff --git a/src/plone/restapi/tests/test_serializer_catalog.py b/src/plone/restapi/tests/test_serializer_catalog.py index 67b0604aea..0e3339fd5f 100644 --- a/src/plone/restapi/tests/test_serializer_catalog.py +++ b/src/plone/restapi/tests/test_serializer_catalog.py @@ -1,6 +1,5 @@ from DateTime import DateTime -from pkg_resources import get_distribution -from pkg_resources import parse_version +from importlib.metadata import distribution from plone.dexterity.utils import createContentInContainer from plone.restapi.interfaces import ISerializeToJson from plone.restapi.interfaces import ISerializeToJsonSummary @@ -9,12 +8,13 @@ from Products.CMFCore.utils import getToolByName from zope.component import getMultiAdapter +import packaging import unittest -HAS_PLONE_6 = parse_version( - get_distribution("Products.CMFPlone").version -) >= parse_version("6.0.0a1") +HAS_PLONE_6 = packaging.version.parse( + distribution("Products.CMFPlone").version +) >= packaging.version.parse("6.0.0a1") class TestCatalogSerializers(unittest.TestCase): From f8599f7edccebe0b4781f195d3dc06b9810600b0 Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Sat, 1 Mar 2025 23:03:53 +0100 Subject: [PATCH 2/6] chore: adjust dependencies --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 97146b4a69..35017ef04d 100644 --- a/setup.py +++ b/setup.py @@ -91,7 +91,7 @@ def read(filename): zip_safe=False, install_requires=[ "setuptools", - "importlib-metadata; python_version<'3.8'", + "packaging", "python-dateutil", "plone.rest", # json renderer moved to plone.restapi "plone.schema>=1.2.1", # new/fixed json field From ba5c358bfbc71425d1572c3e0648af5d62ad183e Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Sat, 1 Mar 2025 22:54:19 +0100 Subject: [PATCH 3/6] Add news entry --- news/4126.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/4126.bugfix diff --git a/news/4126.bugfix b/news/4126.bugfix new file mode 100644 index 0000000000..488c5838bb --- /dev/null +++ b/news/4126.bugfix @@ -0,0 +1 @@ +Replace `pkg_resources` with `importlib.metadata`/`importlib.resources`/`packaging` @gforcada From eef644e0dd0498ee9b3c689b294fb8105f3f4382 Mon Sep 17 00:00:00 2001 From: David Glick Date: Sun, 9 Mar 2025 16:10:20 -0700 Subject: [PATCH 4/6] Just use relative paths instead of importlib.resources (py3.8 compat) --- src/plone/restapi/tests/test_documentation.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plone/restapi/tests/test_documentation.py b/src/plone/restapi/tests/test_documentation.py index 026a775d70..c9d0acd09a 100644 --- a/src/plone/restapi/tests/test_documentation.py +++ b/src/plone/restapi/tests/test_documentation.py @@ -1,7 +1,6 @@ from base64 import b64encode from datetime import datetime from datetime import timezone -from importlib.resources import files from plone import api from plone.app.discussion.interfaces import ICommentAddedEvent from plone.app.discussion.interfaces import IConversation @@ -49,6 +48,7 @@ import io import json import os +import pathlib import re import transaction import unittest @@ -74,8 +74,7 @@ RESPONSE_HEADER_KEYS = ["content-type", "allow", "location"] + TUS_HEADERS - -base_path = str(files("plone.restapi").joinpath("tests/http-examples")) +base_path = str(pathlib.Path(__file__).parent / "http-examples") UPLOAD_DATA = b"abcdefgh" UPLOAD_MIMETYPE = b"text/plain" From 7677ce883b602752002577aa722b186658dd68de Mon Sep 17 00:00:00 2001 From: David Glick Date: Sun, 9 Mar 2025 16:17:01 -0700 Subject: [PATCH 5/6] Get docs version dynamically --- Makefile | 2 +- docs/source/conf.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index b94538b84a..679df9fd6c 100644 --- a/Makefile +++ b/Makefile @@ -144,7 +144,7 @@ docs-clean: ## Clean current and legacy docs build directories rm -rf docs/build $(BIN_FOLDER)/sphinx-autobuild $(BIN_FOLDER)/sphinx-build: $(BIN_FOLDER)/pip ## Install dependencies for building docs - $(BIN_FOLDER)/pip install -r requirements-docs.txt + $(BIN_FOLDER)/pip install -r requirements-docs.txt -r requirements.txt .PHONY: docs-livehtml docs-livehtml: $(BIN_FOLDER)/sphinx-autobuild ## Rebuild Sphinx documentation on changes, with live-reload in the browser diff --git a/docs/source/conf.py b/docs/source/conf.py index 08cebeb6f4..a960cc8e35 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -10,6 +10,8 @@ # All configuration values have a default; values that are commented out # serve to show the default. +from importlib.metadata import version + import datetime # If extensions (or modules to document with autodoc) are in another directory, @@ -34,9 +36,7 @@ # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. -# TODO: There must be a way to import this from `setup.py` so we don't have to -# update it manually for each release. -version = "9.7.2.dev0" +version = release = version("plone.restapi") release = version # -- General configuration ---------------------------------------------------- From c384a354fad0aab700825a2327c4f2cc6982ed1e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 9 Mar 2025 17:46:12 -0700 Subject: [PATCH 6/6] Remove redundant line --- docs/source/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index a960cc8e35..f4f056d228 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -37,7 +37,6 @@ # |version| and |release|, also used in various other places throughout the # built documents. version = release = version("plone.restapi") -release = version # -- General configuration ----------------------------------------------------