Source code for hbutils.model.compare

"""
Comparable object utilities.

This module provides a lightweight base interface for implementing rich
comparison operations on custom objects. Subclasses only need to implement
the :meth:`IComparable._cmpkey` method, and all comparison operators
(``==``, ``!=``, ``<``, ``<=``, ``>``, ``>=``) will be derived from it.

The module contains the following main components:

* :class:`IComparable` - Base interface for defining comparable objects

Example::

    >>> from hbutils.model.compare import IComparable
    >>> class MyValue(IComparable):
    ...     def __init__(self, v: int) -> None:
    ...         self._v = v
    ...
    ...     def _cmpkey(self):
    ...         return self._v
    ...
    >>> MyValue(1) < MyValue(2)
    True
"""

import operator as ops
from typing import Any, Callable

__all__ = [
    'IComparable',
]


[docs] class IComparable: """ Interface for a comparable object. This class provides a base interface for creating comparable objects. Subclasses only need to implement the :meth:`_cmpkey` method to enable all comparison operations. The comparison is based on the key values returned by :meth:`_cmpkey`. Examples:: >>> from hbutils.model import IComparable >>> class MyValue(IComparable): ... def __init__(self, v) -> None: ... self._v = v ... ... def _cmpkey(self): ... return self._v ... >>> MyValue(1) == MyValue(1) True >>> MyValue(1) == MyValue(2) False >>> MyValue(1) != MyValue(2) True >>> MyValue(1) > MyValue(2) False >>> MyValue(1) >= MyValue(2) False >>> MyValue(1) < MyValue(2) True >>> MyValue(1) <= MyValue(2) True """ def _cmpkey(self) -> Any: """ Function for getting a key value which is used for comparison. :return: A value used to compare. :rtype: Any :raises NotImplementedError: This method must be implemented by subclasses. .. note:: Subclasses must override this method to return a comparable value that represents the object for comparison purposes. """ raise NotImplementedError # pragma: no cover def _cmpcheck(self, op: Callable[[Any, Any], bool], other: Any, default: bool = False) -> bool: """ Internal method to perform comparison check between two objects. :param op: The comparison operator function to apply. :type op: callable :param other: The other object to compare with. :type other: object :param default: The default value to return if types don't match. :type default: bool :return: Result of the comparison operation. :rtype: bool .. note:: This method checks if both objects are of the same type before performing the comparison. If types differ, it returns the default value. """ if type(self) == type(other): return op(self._cmpkey(), other._cmpkey()) else: return default
[docs] def __eq__(self, other: Any) -> bool: """ Check equality between two objects. :param other: The other object to compare with. :type other: object :return: True if objects are equal, False otherwise. :rtype: bool .. note:: Returns True immediately if comparing with self (identity check). Otherwise, compares using :meth:`_cmpkey` values if types match. """ if self is other: return True else: return self._cmpcheck(ops.__eq__, other, default=False)
[docs] def __ne__(self, other: Any) -> bool: """ Check inequality between two objects. :param other: The other object to compare with. :type other: object :return: True if objects are not equal, False otherwise. :rtype: bool .. note:: Returns False immediately if comparing with self (identity check). Otherwise, compares using :meth:`_cmpkey` values if types match. """ if self is other: return False else: return self._cmpcheck(ops.__ne__, other, default=True)
[docs] def __lt__(self, other: Any) -> bool: """ Check if this object is less than another object. :param other: The other object to compare with. :type other: object :return: True if this object is less than other, False otherwise. :rtype: bool """ return self._cmpcheck(ops.__lt__, other)
[docs] def __le__(self, other: Any) -> bool: """ Check if this object is less than or equal to another object. :param other: The other object to compare with. :type other: object :return: True if this object is less than or equal to other, False otherwise. :rtype: bool """ return self._cmpcheck(ops.__le__, other)
[docs] def __gt__(self, other: Any) -> bool: """ Check if this object is greater than another object. :param other: The other object to compare with. :type other: object :return: True if this object is greater than other, False otherwise. :rtype: bool """ return self._cmpcheck(ops.__gt__, other)
[docs] def __ge__(self, other: Any) -> bool: """ Check if this object is greater than or equal to another object. :param other: The other object to compare with. :type other: object :return: True if this object is greater than or equal to other, False otherwise. :rtype: bool """ return self._cmpcheck(ops.__ge__, other)