Author: Antonio Cuni <anto.c...@gmail.com> Branch: Changeset: r53053:bdff1d20bb98 Date: 2012-03-01 16:41 +0100 http://bitbucket.org/pypy/pypy/changeset/bdff1d20bb98/
Log: add a way to automatically define __gt__, __ge__, __le__ and __ne__ on top of the given __lt__ and __eq__ diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -304,6 +304,42 @@ assert_method(w_o1, "c", True) assert_method(w_o2, "c", False) + def test_total_ordering(self): + class W_SomeType(Wrappable): + def __init__(self, space, x): + self.space = space + self.x = x + + def descr__lt(self, w_other): + assert isinstance(w_other, W_SomeType) + return self.space.wrap(self.x < w_other.x) + + def descr__eq(self, w_other): + assert isinstance(w_other, W_SomeType) + return self.space.wrap(self.x == w_other.x) + + W_SomeType.typedef = typedef.TypeDef( + 'some_type', + __total_ordering__ = 'auto', + __lt__ = interp2app(W_SomeType.descr__lt), + __eq__ = interp2app(W_SomeType.descr__eq), + ) + space = self.space + w_b = space.wrap(W_SomeType(space, 2)) + w_c = space.wrap(W_SomeType(space, 2)) + w_a = space.wrap(W_SomeType(space, 1)) + # explicitly defined + assert space.is_true(space.lt(w_a, w_b)) + assert not space.is_true(space.eq(w_a, w_b)) + assert space.is_true(space.eq(w_b, w_c)) + # automatically defined + assert space.is_true(space.le(w_a, w_b)) + assert space.is_true(space.le(w_b, w_c)) + assert space.is_true(space.gt(w_b, w_a)) + assert space.is_true(space.ge(w_b, w_a)) + assert space.is_true(space.ge(w_b, w_c)) + assert space.is_true(space.ne(w_a, w_b)) + assert not space.is_true(space.ne(w_b, w_c)) class AppTestTypeDef: diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -12,7 +12,7 @@ from pypy.rlib.jit import promote class TypeDef: - def __init__(self, __name, __base=None, **rawdict): + def __init__(self, __name, __base=None, __total_ordering__=None, **rawdict): "NOT_RPYTHON: initialization-time only" self.name = __name if __base is None: @@ -34,6 +34,9 @@ # xxx used by faking self.fakedcpytype = None self.add_entries(**rawdict) + assert __total_ordering__ in (None, 'auto'), "Unknown value for __total_ordering" + if __total_ordering__ == 'auto': + self.auto_total_ordering() def add_entries(self, **rawdict): # xxx fix the names of the methods to match what app-level expects @@ -41,7 +44,15 @@ if isinstance(value, (interp2app, GetSetProperty)): value.name = key self.rawdict.update(rawdict) - + + def auto_total_ordering(self): + assert '__lt__' in self.rawdict, "__total_ordering='auto' requires __lt__" + assert '__eq__' in self.rawdict, "__total_ordering='auto' requires __eq__" + self.add_entries(__le__ = auto__le__, + __gt__ = auto__gt__, + __ge__ = auto__ge__, + __ne__ = auto__ne__) + def _freeze_(self): # hint for the annotator: track individual constant instances of TypeDef return True @@ -50,6 +61,27 @@ return "<%s name=%r>" % (self.__class__.__name__, self.name) +# generic special cmp methods defined on top of __lt__ and __eq__, used by +# automatic total ordering + +@interp2app +def auto__le__(space, w_self, w_other): + return space.or_(space.lt(w_self, w_other), + space.eq(w_self, w_other)) + +@interp2app +def auto__gt__(space, w_self, w_other): + return space.not_(space.le(w_self, w_other)) + +@interp2app +def auto__ge__(space, w_self, w_other): + return space.not_(space.lt(w_self, w_other)) + +@interp2app +def auto__ne__(space, w_self, w_other): + return space.not_(space.eq(w_self, w_other)) + + # ____________________________________________________________ # Hash support _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit