commit:     dfd645f6be262d422d9be67c4b8cd408cf627ec5
Author:     Brian Harring <ferringb <AT> gmail <DOT> com>
AuthorDate: Mon Oct 27 13:20:25 2025 +0000
Commit:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
CommitDate: Mon Oct 27 21:38:37 2025 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/snakeoil.git/commit/?id=dfd645f6

feat: deprecate inject_richcmp_from_cmp .  Use either GenericRichComparison or 
total_ordering

GenericRichComparison is specialized against the underlying __attr_comparison__ 
logic,
barring that, just use functools.total_ordering.

I expect the main (sole?) user of GenericRichComparison will be CPV and atom
classes, since pulling their __cmp__ usage apart will be a PITA.

Signed-off-by: Brian Harring <ferringb <AT> gmail.com>

 src/snakeoil/klass/__init__.py   | 87 +++-------------------------------------
 src/snakeoil/klass/deprecated.py | 83 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 81 deletions(-)

diff --git a/src/snakeoil/klass/__init__.py b/src/snakeoil/klass/__init__.py
index af3e007..9691dd9 100644
--- a/src/snakeoil/klass/__init__.py
+++ b/src/snakeoil/klass/__init__.py
@@ -47,7 +47,12 @@ from typing import Any
 from snakeoil.deprecation import deprecated as warn_deprecated
 
 from ..caching import WeakInstMeta
-from .deprecated import ImmutableInstance, immutable_instance, 
inject_immutable_instance
+from .deprecated import (
+    ImmutableInstance,
+    immutable_instance,
+    inject_immutable_instance,
+    inject_richcmp_methods_from_cmp,
+)
 from .properties import (
     _uncached_singleton,  # noqa: F401 .  This exists purely due to a stupid 
usage of pkgcore.ebuild.profile which is being removed.
     alias,
@@ -238,86 +243,6 @@ def generic_equality(
     return real_type(name, bases, scope)
 
 
-def generic_lt(self, other):
-    """generic implementation of __lt__ that uses __cmp__"""
-    return self.__cmp__(other) < 0
-
-
-def generic_le(self, other):
-    """reflective implementation of __le__ that uses __cmp__"""
-    return self.__cmp__(other) <= 0
-
-
-def generic_eq(self, other):
-    """reflective implementation of __eq__ that uses __cmp__"""
-    return self.__cmp__(other) == 0
-
-
-def generic_ne(self, other):
-    """reflective implementation of __ne__ that uses __cmp__"""
-    return self.__cmp__(other) != 0
-
-
-def generic_ge(self, other):
-    """reflective implementation of __ge__ that uses __cmp__"""
-    return self.__cmp__(other) >= 0
-
-
-def generic_gt(self, other):
-    """reflective implementation of __gt__ that uses __cmp__"""
-    return self.__cmp__(other) > 0
-
-
-def inject_richcmp_methods_from_cmp(scope):
-    """
-    class namespace modifier injecting richcmp methods that rely on __cmp__ 
for py3k
-    compatibility
-
-    Note that this just injects generic implementations such as 
:py:func:`generic_lt`;
-    if a method already exists, it will not override it.  This behavior is 
primarily
-    beneficial if the developer wants to optimize one specific method- __lt__ 
for sorting
-    reasons for example, but performance is less of a concern for the other
-    rich comparison methods.
-
-    Example usage:
-
-    >>> from snakeoil.klass import inject_richcmp_methods_from_cmp
-    >>> from snakeoil.compatibility import cmp
-    >>> class foo:
-    ...
-    ...   # note that for this example, we inject always since we're
-    ...   # explicitly accessing __ge__ methods- under py2k, they wouldn't
-    ...   # exist (__cmp__ would be sufficient).
-    ...
-    ...   # add the generic rich comparsion methods to the local class 
namespace
-    ...   inject_richcmp_methods_from_cmp(locals())
-    ...
-    ...   def __init__(self, a, b):
-    ...     self.a, self.b = a, b
-    ...
-    ...   def __cmp__(self, other):
-    ...     c = cmp(self.a, other.a)
-    ...     if c == 0:
-    ...       c = cmp(self.b, other.b)
-    ...     return c
-    >>>
-    >>> assert foo(1, 2).__ge__(foo(1, 1))
-    >>> assert foo(1, 1).__eq__(foo(1, 1))
-
-    :param scope: the modifiable scope of a class namespace to work on
-    """
-
-    for key, func in (
-        ("__lt__", generic_lt),
-        ("__le__", generic_le),
-        ("__eq__", generic_eq),
-        ("__ne__", generic_ne),
-        ("__ge__", generic_ge),
-        ("__gt__", generic_gt),
-    ):
-        scope.setdefault(key, func)
-
-
 @warn_deprecated(
     "snakeoil.klass.chained_getter is deprecated.  Use operator.attrgetter 
instead."
 )

diff --git a/src/snakeoil/klass/deprecated.py b/src/snakeoil/klass/deprecated.py
index cb7811a..9c9d5a1 100644
--- a/src/snakeoil/klass/deprecated.py
+++ b/src/snakeoil/klass/deprecated.py
@@ -51,3 +51,86 @@ def inject_immutable_instance(scope: dict[str, typing.Any]):
     """
     scope.setdefault("__setattr__", ImmutableInstance.__setattr__)
     scope.setdefault("__delattr__", ImmutableInstance.__delattr__)
+
+
+def __generic_lt(self, other):
+    """generic implementation of __lt__ that uses __cmp__"""
+    return self.__cmp__(other) < 0
+
+
+def __generic_le(self, other):
+    """reflective implementation of __le__ that uses __cmp__"""
+    return self.__cmp__(other) <= 0
+
+
+def __generic_eq(self, other):
+    """reflective implementation of __eq__ that uses __cmp__"""
+    return self.__cmp__(other) == 0
+
+
+def __generic_ne(self, other):
+    """reflective implementation of __ne__ that uses __cmp__"""
+    return self.__cmp__(other) != 0
+
+
+def __generic_ge(self, other):
+    """reflective implementation of __ge__ that uses __cmp__"""
+    return self.__cmp__(other) >= 0
+
+
+def __generic_gt(self, other):
+    """reflective implementation of __gt__ that uses __cmp__"""
+    return self.__cmp__(other) > 0
+
+
+@deprecated(
+    "inject_richcmp_methods_from_cmp is deprecated, migrate to 
functools.total_ordering instead."
+)
+def inject_richcmp_methods_from_cmp(scope):
+    """
+    class namespace modifier injecting richcmp methods that rely on __cmp__ 
for py3k
+    compatibility
+
+    Note that this just injects generic implementations such as 
:py:func:`__generic_lt`;
+    if a method already exists, it will not override it.  This behavior is 
primarily
+    beneficial if the developer wants to optimize one specific method- __lt__ 
for sorting
+    reasons for example, but performance is less of a concern for the other
+    rich comparison methods.
+
+    Example usage:
+
+    >>> from snakeoil.klass import inject_richcmp_methods_from_cmp
+    >>> from snakeoil.compatibility import cmp
+    >>> class foo:
+    ...
+    ...   # note that for this example, we inject always since we're
+    ...   # explicitly accessing __ge__ methods- under py2k, they wouldn't
+    ...   # exist (__cmp__ would be sufficient).
+    ...
+    ...   # add the generic rich comparsion methods to the local class 
namespace
+    ...   inject_richcmp_methods_from_cmp(locals())
+    ...
+    ...   def __init__(self, a, b):
+    ...     self.a, self.b = a, b
+    ...
+    ...   def __cmp__(self, other):
+    ...     c = cmp(self.a, other.a)
+    ...     if c == 0:
+    ...       c = cmp(self.b, other.b)
+    ...     return c
+    >>>
+    >>> assert foo(1, 2).__ge__(foo(1, 1))
+    >>> assert foo(1, 1).__eq__(foo(1, 1))
+
+    :param scope: the modifiable scope of a class namespace to work on
+    """
+
+    for key, func in (
+        ("__lt__", __generic_lt),
+        ("__le__", __generic_le),
+        ("__eq__", __generic_eq),
+        ("__ne__", __generic_ne),
+        ("__ge__", __generic_ge),
+        ("__gt__", __generic_gt),
+    ):
+        scope.setdefault(key, func)

Reply via email to