git: c4dd8f401752 - main - devel/py-setuptools@py39: add py39 compat layer to vendored importlib-metadata

From: Charlie Li <vishwin_at_FreeBSD.org>
Date: Thu, 10 Apr 2025 17:50:36 UTC
The branch main has been updated by vishwin:

URL: https://cgit.FreeBSD.org/ports/commit/?id=c4dd8f40175252743857e936c56c1c8740202230

commit c4dd8f40175252743857e936c56c1c8740202230
Author:     Charlie Li <vishwin@FreeBSD.org>
AuthorDate: 2025-04-10 17:41:54 +0000
Commit:     Charlie Li <vishwin@FreeBSD.org>
CommitDate: 2025-04-10 17:50:23 +0000

    devel/py-setuptools@py39: add py39 compat layer to vendored importlib-metadata
    
    ...and partially revert a setuptools commit exposing another error.
    
    Context: https://github.com/pypa/setuptools/issues/3452
    
    Reported by: Niels Kobschätzki
    PR: 285909
---
 devel/py-setuptools/Makefile                       |  8 +++-
 ...ls___vendor_importlib__metadata_____init____.py | 41 +++++++++++++++++
 ...ls___vendor_importlib__metadata___py39compat.py | 51 ++++++++++++++++++++++
 .../files/py39/patch-setuptools_dist.py            | 14 ++++++
 4 files changed, 113 insertions(+), 1 deletion(-)

diff --git a/devel/py-setuptools/Makefile b/devel/py-setuptools/Makefile
index f8441337aa21..3cd00ac478de 100644
--- a/devel/py-setuptools/Makefile
+++ b/devel/py-setuptools/Makefile
@@ -29,4 +29,10 @@ CPE_VENDOR=	python
 
 NO_ARCH=	yes
 
-.include <bsd.port.mk>
+.include <bsd.port.pre.mk>
+
+.if ${PYTHON_REL} < 31000
+EXTRA_PATCHES+=	${PATCHDIR}/py39
+.endif
+
+.include <bsd.port.post.mk>
diff --git a/devel/py-setuptools/files/py39/patch-setuptools___vendor_importlib__metadata_____init____.py b/devel/py-setuptools/files/py39/patch-setuptools___vendor_importlib__metadata_____init____.py
new file mode 100644
index 000000000000..70368aad04ff
--- /dev/null
+++ b/devel/py-setuptools/files/py39/patch-setuptools___vendor_importlib__metadata_____init____.py
@@ -0,0 +1,41 @@
+--- setuptools/_vendor/importlib_metadata/__init__.py.orig	2022-07-04 02:25:25 UTC
++++ setuptools/_vendor/importlib_metadata/__init__.py
+@@ -14,7 +14,7 @@ import collections
+ import posixpath
+ import collections
+ 
+-from . import _adapters, _meta
++from . import _adapters, _meta, _py39compat
+ from ._collections import FreezableDefaultDict, Pair
+ from ._compat import (
+     NullFinder,
+@@ -180,6 +180,10 @@ class EntryPoint(DeprecatedTuple):
+     following the attr, and following any extras.
+     """
+ 
++    name: str
++    value: str
++    group: str
++
+     dist: Optional['Distribution'] = None
+ 
+     def __init__(self, name, value, group):
+@@ -350,7 +354,8 @@ class EntryPoints(DeprecatedList):
+         Select entry points from self that match the
+         given parameters (typically group and/or name).
+         """
+-        return EntryPoints(ep for ep in self if ep.matches(**params))
++        candidates = (_py39compat.ep_matches(ep, **params) for ep in self)
++        return EntryPoints(ep for ep, predicate in candidates if predicate)
+ 
+     @property
+     def names(self):
+@@ -991,7 +996,7 @@ def entry_points(**params) -> Union[EntryPoints, Selec
+ 
+     :return: EntryPoints or SelectableGroups for all installed packages.
+     """
+-    norm_name = operator.attrgetter('_normalized_name')
++    norm_name = _py39compat.normalized_name
+     unique = functools.partial(unique_everseen, key=norm_name)
+     eps = itertools.chain.from_iterable(
+         dist.entry_points for dist in unique(distributions())
diff --git a/devel/py-setuptools/files/py39/patch-setuptools___vendor_importlib__metadata___py39compat.py b/devel/py-setuptools/files/py39/patch-setuptools___vendor_importlib__metadata___py39compat.py
new file mode 100644
index 000000000000..ce7b7d034c54
--- /dev/null
+++ b/devel/py-setuptools/files/py39/patch-setuptools___vendor_importlib__metadata___py39compat.py
@@ -0,0 +1,51 @@
+--- setuptools/_vendor/importlib_metadata/_py39compat.py.orig	2025-04-10 14:12:41 UTC
++++ setuptools/_vendor/importlib_metadata/_py39compat.py
+@@ -0,0 +1,48 @@
++"""
++Compatibility layer with Python 3.8/3.9
++"""
++from typing import TYPE_CHECKING, Any, Optional, Tuple
++
++if TYPE_CHECKING:  # pragma: no cover
++    # Prevent circular imports on runtime.
++    from . import Distribution, EntryPoint
++else:
++    Distribution = EntryPoint = Any
++
++
++def normalized_name(dist: Distribution) -> Optional[str]:
++    """
++    Honor name normalization for distributions that don't provide ``_normalized_name``.
++    """
++    try:
++        return dist._normalized_name
++    except AttributeError:
++        from . import Prepared  # -> delay to prevent circular imports.
++
++        return Prepared.normalize(getattr(dist, "name", None) or dist.metadata['Name'])
++
++
++def ep_matches(ep: EntryPoint, **params) -> Tuple[EntryPoint, bool]:
++    """
++    Workaround for ``EntryPoint`` objects without the ``matches`` method.
++    For the sake of convenience, a tuple is returned containing not only the
++    boolean value corresponding to the predicate evalutation, but also a compatible
++    ``EntryPoint`` object that can be safely used at a later stage.
++
++    For example, the following sequences of expressions should be compatible:
++
++        # Sequence 1: using the compatibility layer
++        candidates = (_py39compat.ep_matches(ep, **params) for ep in entry_points)
++        [ep for ep, predicate in candidates if predicate]
++
++        # Sequence 2: using Python 3.9+
++        [ep for ep in entry_points if ep.matches(**params)]
++    """
++    try:
++        return ep, ep.matches(**params)
++    except AttributeError:
++        from . import EntryPoint  # -> delay to prevent circular imports.
++
++        # Reconstruct the EntryPoint object to make sure it is compatible.
++        _ep = EntryPoint(ep.name, ep.value, ep.group)
++        return _ep, _ep.matches(**params)
diff --git a/devel/py-setuptools/files/py39/patch-setuptools_dist.py b/devel/py-setuptools/files/py39/patch-setuptools_dist.py
new file mode 100644
index 000000000000..d84f76b41162
--- /dev/null
+++ b/devel/py-setuptools/files/py39/patch-setuptools_dist.py
@@ -0,0 +1,14 @@
+--- setuptools/dist.py.orig	2022-07-04 02:25:25 UTC
++++ setuptools/dist.py
+@@ -777,8 +777,9 @@ class Distribution(_Distribution):
+ 
+     def _setuptools_commands(self):
+         try:
+-            return metadata.distribution('setuptools').entry_points.names
+-        except metadata.PackageNotFoundError:
++            dist = pkg_resources.get_distribution('setuptools')
++            return list(dist.get_entry_map('distutils.commands'))
++        except pkg_resources.DistributionNotFound:
+             # during bootstrapping, distribution doesn't exist
+             return []
+