From 11fcc50ad909808087082f1d7fadbc22aec13c36 Mon Sep 17 00:00:00 2001
From: Andre Anjos <andre.dos.anjos@gmail.com>
Date: Sat, 23 Mar 2024 12:22:44 +0100
Subject: [PATCH] [gitlab.release] Depend on packaging instead of setuptools

---
 doc/nitpick-exceptions.txt            |  3 +-
 src/idiap_devtools/gitlab/release.py  | 43 +++++++++++++--------------
 src/idiap_devtools/profile.py         |  8 +++--
 src/idiap_devtools/scripts/fullenv.py |  3 +-
 tests/test_release.py                 |  2 +-
 5 files changed, 29 insertions(+), 30 deletions(-)

diff --git a/doc/nitpick-exceptions.txt b/doc/nitpick-exceptions.txt
index 0af3c73..fbcc656 100644
--- a/doc/nitpick-exceptions.txt
+++ b/doc/nitpick-exceptions.txt
@@ -3,7 +3,6 @@
 # SPDX-License-Identifier: BSD-3-Clause
 
 py:class conda_build.config.Config
-py:class pkg_resources.Requirement
+py:class packaging.requirements.Requirement
 py:class os._Environ
 py:class _io.StringIO
-py:class packaging.requirements.Requirement
diff --git a/src/idiap_devtools/gitlab/release.py b/src/idiap_devtools/gitlab/release.py
index e14656a..8a485db 100644
--- a/src/idiap_devtools/gitlab/release.py
+++ b/src/idiap_devtools/gitlab/release.py
@@ -12,11 +12,11 @@ from distutils.version import StrictVersion
 
 import gitlab
 import gitlab.v4.objects
+import packaging.requirements
 import packaging.version
 import tomlkit
 
 from git import Repo
-from pkg_resources import Requirement
 
 from idiap_devtools.profile import Profile
 
@@ -95,7 +95,7 @@ def _update_readme(
 
 def _pin_versions_of_packages_list(
     packages_list: list[str],
-    dependencies_versions: list[Requirement],
+    dependencies_versions: list[packaging.requirements.Requirement],
 ) -> list[str]:
     """Add its version to each package according to a dictionary of versions.
 
@@ -127,15 +127,15 @@ def _pin_versions_of_packages_list(
     # Check that there is not the same dependency twice in the pins
     seen = set()
     for d in dependencies_versions:
-        if d.key in seen:
+        if d.name in seen:
             raise NotImplementedError(
                 "Pinning with more than one specification per dependency not"
                 "supported."
             )
-        seen.add(d.key)
+        seen.add(d.name)
 
     # Make it easier to retrieve the dependency pin for each package.
-    dependencies_dict = {d.key: d for d in dependencies_versions}
+    dependencies_dict = {d.name: d for d in dependencies_versions}
 
     results = []
 
@@ -144,31 +144,31 @@ def _pin_versions_of_packages_list(
         results.append(package)
 
         # Get the dependency package version specifier if already present.
-        pkg_req = Requirement.parse(package)
+        pkg_req = packaging.requirements.Requirement(package)
 
         if pkg_req.url is not None:
             logger.warning(
                 "Ignoring dependency '%s' as it is specified with a url (%s).",
-                pkg_req.key,
+                pkg_req.name,
                 pkg_req.url,
             )
 
         # Retrieve this dependency's constraint Requirement object
-        desired_pin = dependencies_dict.get(pkg_req.key)
+        desired_pin = dependencies_dict.get(pkg_req.name)
 
         if desired_pin is None:
             logger.warning(
                 "Dependency '%s' is not available in constraints. Skipping "
                 "pinning. Consider adding this package to your dev-profile "
                 "constraints file.",
-                pkg_req.key,
+                pkg_req.name,
             )
             continue
 
         # A Requirement is composed of:
-        #   key[extras]@ url ; marker
+        #   name[extras]@ url ; marker
         # Or
-        #   key[extras]specifier; marker
+        #   name[extras]specifier; marker
         # Where extras and marker are optional
 
         # The following handles those different fields
@@ -176,29 +176,26 @@ def _pin_versions_of_packages_list(
         if desired_pin.url is not None:
             logger.info(
                 "Pinning of %s will be done with a URL (%s).",
-                pkg_req.key,
+                pkg_req.name,
                 desired_pin.url,
             )
         else:
             # Build the 'specs' field
-            if len(desired_pin.specs) == 0:
+            if not desired_pin.specifier:
                 logger.warning(
                     "Dependency '%s' has no version specifier in constraints "
                     "'%s'. Skipping pinning.",
-                    pkg_req.key,
+                    pkg_req.name,
                     desired_pin,
                 )
                 continue
 
             # If version specifiers are already present in that dependency
-            if len(pkg_req.specs) > 0:
+            if pkg_req.specifier:
                 raise ValueError(
                     f"You cannot specify a version for the dependency {pkg_req}"
                 )
-            desired_specs = desired_pin.specs
-
-            # Set the version of that dependency to the pinned one.
-            specs_str = ",".join("".join(s) for s in desired_specs)
+            specs_str = str(desired_pin.specifier)
 
         # Build the 'marker' field
         if pkg_req.marker is not None:
@@ -225,7 +222,7 @@ def _pin_versions_of_packages_list(
         if desired_pin.url is not None:
             final_str = "".join(
                 (
-                    pkg_req.key,
+                    pkg_req.name,
                     extras_str,
                     "@ ",
                     desired_pin.url,
@@ -235,11 +232,13 @@ def _pin_versions_of_packages_list(
             )
         else:
             final_str = "".join(
-                (pkg_req.key, extras_str, specs_str, marker_str)
+                (pkg_req.name, extras_str, specs_str, marker_str)
             )
 
         # Replace the package specification with the pinned version
-        packages_list[pkg_id] = str(Requirement.parse(final_str))
+        packages_list[pkg_id] = str(
+            packaging.requirements.Requirement(final_str)
+        )
         logger.debug("Package pinned: %s", packages_list[pkg_id])
 
     return packages_list
diff --git a/src/idiap_devtools/profile.py b/src/idiap_devtools/profile.py
index b242241..acc9fd8 100644
--- a/src/idiap_devtools/profile.py
+++ b/src/idiap_devtools/profile.py
@@ -6,7 +6,7 @@ import io
 import pathlib
 import typing
 
-import pkg_resources
+import packaging.requirements
 import tomli
 import xdg
 import yaml
@@ -325,11 +325,13 @@ class Profile:
             for p, v in package_pins.items()
         }
 
-    def python_constraints(self) -> list[pkg_resources.Requirement] | None:
+    def python_constraints(
+        self,
+    ) -> list[packaging.requirements.Requirement] | None:
         """Return a list of Python requirements given the current profile."""
         content = self.get_file_contents(("python", "constraints"))
 
         if content is None:
             return None
 
-        return list(pkg_resources.parse_requirements(content))
+        return [packaging.requirements.Requirement(k) for k in content.split()]
diff --git a/src/idiap_devtools/scripts/fullenv.py b/src/idiap_devtools/scripts/fullenv.py
index a39bdf2..9366478 100644
--- a/src/idiap_devtools/scripts/fullenv.py
+++ b/src/idiap_devtools/scripts/fullenv.py
@@ -123,8 +123,7 @@ def fullenv(
     python_packages = [
         k
         for k in python_packages
-        if python_to_conda.get(k.project_name, k.project_name)
-        not in conda_packages
+        if python_to_conda.get(k.name, k.name) not in conda_packages
     ]
 
     data: dict[str, typing.Any] = dict(channels=["conda-forge"])
diff --git a/tests/test_release.py b/tests/test_release.py
index 1b5099c..1d1f493 100644
--- a/tests/test_release.py
+++ b/tests/test_release.py
@@ -5,7 +5,7 @@
 import pytest
 
 from idiap_devtools.gitlab import release
-from pkg_resources import Requirement
+from packaging.requirements import Requirement
 
 
 def test_pinning_no_constraints():
-- 
GitLab