4242from functools import wraps
4343from importlib import import_module
4444from operator import attrgetter
45- from typing import Any
4645
4746from snakeoil .deprecation import deprecated as warn_deprecated
4847
@@ -167,14 +166,22 @@ def __attr_comparison__(self) -> tuple[str, ...]: # pyright: ignore[reportRedec
167166
168167 __attr_comparison__ : tuple [str , ...]
169168
170- def __eq__ (self , other : Any ) -> bool :
169+ def __eq__ (
170+ self , value , / , attr_comparison_override : tuple [str , ...] | None = None
171+ ) -> bool :
171172 """
172- Comparison is down via comparing attributes listed in self.__attr_comparison__
173+ Comparison is down via comparing attributes listed in self.__attr_comparison__,
174+ or via the passed in attr_comparison_override. That exists specifically to
175+ simplify subclass partial reuse of the class when logic gets complex.
173176 """
174- if self is other :
177+ if self is value :
175178 return True
176- for attr in self .__attr_comparison__ :
177- if getattr (self , attr , sentinel ) != getattr (other , attr , sentinel ):
179+ for attr in (
180+ self .__attr_comparison__
181+ if attr_comparison_override is None
182+ else attr_comparison_override
183+ ):
184+ if getattr (self , attr , sentinel ) != getattr (value , attr , sentinel ):
178185 return False
179186 return True
180187
@@ -195,6 +202,56 @@ def __init_subclass__(cls) -> None:
195202 return super ().__init_subclass__ ()
196203
197204
205+ class GenericRichComparison (GenericEquality ):
206+ __slots__ = ()
207+
208+ def __lt__ (self , value , attr_comparison_override : tuple [str , ...] | None = None ):
209+ if self is value :
210+ return False
211+ attrlist = (
212+ self .__attr_comparison__
213+ if attr_comparison_override is None
214+ else attr_comparison_override
215+ )
216+ for attr in attrlist :
217+ obj1 , obj2 = getattr (self , attr , sentinel ), getattr (value , attr , sentinel )
218+ if obj1 is sentinel :
219+ if obj2 is sentinel :
220+ continue
221+ return True
222+ elif obj2 is sentinel :
223+ return False
224+ if not (obj1 >= obj2 ): # pyright: ignore[reportOperatorIssue]
225+ return True
226+ return False
227+
228+ def __le__ (self , value , attr_comparison_override : tuple [str , ...] | None = None ):
229+ if self is value :
230+ return True
231+ attrlist = (
232+ self .__attr_comparison__
233+ if attr_comparison_override is None
234+ else attr_comparison_override
235+ )
236+ for attr in attrlist :
237+ obj1 , obj2 = getattr (self , attr , sentinel ), getattr (value , attr , sentinel )
238+ if obj1 is sentinel :
239+ if obj2 is sentinel :
240+ continue
241+ return True
242+ elif obj2 is sentinel :
243+ return False
244+ if not (obj1 > obj2 ): # pyright: ignore[reportOperatorIssue]
245+ return True
246+ return False
247+
248+ def __gt__ (self , value , attr_comparison_override : tuple [str , ...] | None = None ):
249+ return not self .__le__ (value , attr_comparison_override = attr_comparison_override )
250+
251+ def __ge__ (self , value , attr_comparison_override : tuple [str , ...] | None = None ):
252+ return not self .__lt__ (value , attr_comparison_override = attr_comparison_override )
253+
254+
198255@warn_deprecated (
199256 "generic_equality metaclass usage is deprecated; inherit from snakeoil.klass.GenericEquality instead."
200257)
0 commit comments