1# mode: run
2
3import cython
4compiled = cython.compiled
5
6import sys
7IS_PY2 = sys.version_info[0] == 2
8
9
10@cython.cclass
11class X(object):
12    x = cython.declare(cython.int)
13
14    def __init__(self, x):
15        self.x = x
16
17    def __repr__(self):
18        return "<%d>" % self.x
19
20
21@cython.cfunc
22@cython.locals(x=X)
23def x_of(x):
24    return x.x
25
26
27@cython.cclass
28class ClassEq(X):
29    """
30    >>> a = ClassEq(1)
31    >>> b = ClassEq(2)
32    >>> c = ClassEq(1)
33    >>> a == a
34    True
35    >>> a != a
36    False
37
38    >>> a == b
39    False
40    >>> a != b
41    True
42
43    >>> a == c
44    True
45    >>> if IS_PY2 and not compiled: a is c
46    ... else: a != c
47    False
48
49    >>> b == c
50    False
51    >>> b != c
52    True
53
54    >>> c == a
55    True
56    >>> if IS_PY2 and not compiled: c is a
57    ... else: c != a
58    False
59
60    >>> b == a
61    False
62    >>> b != a
63    True
64
65    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
66    ... else: a < b
67    Traceback (most recent call last):
68    TypeError...
69    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
70    ... else: a > b
71    Traceback (most recent call last):
72    TypeError...
73    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
74    ... else: a <= b
75    Traceback (most recent call last):
76    TypeError...
77    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
78    ... else: a >= b
79    Traceback (most recent call last):
80    TypeError...
81
82    >>> print(a.__eq__.__doc__)
83    EQ
84    """
85    def __eq__(self, other):
86        """EQ"""
87        assert 1 <= self.x <= 2
88        assert isinstance(self, ClassEq), type(self)
89        if isinstance(other, X):
90            return self.x == x_of(other)
91        elif isinstance(other, int):
92            return self.x < other
93        return NotImplemented
94
95
96@cython.cclass
97class ClassEqNe(ClassEq):
98    """
99    >>> a = ClassEqNe(1)
100    >>> b = ClassEqNe(2)
101    >>> c = ClassEqNe(1)
102    >>> a == a
103    True
104    >>> a != a
105    False
106
107    >>> a == b
108    False
109    >>> a != b
110    True
111
112    >>> a == c
113    True
114    >>> a != c
115    False
116
117    >>> b == c
118    False
119    >>> b != c
120    True
121
122    >>> c == a
123    True
124    >>> c != a
125    False
126
127    >>> b == a
128    False
129    >>> b != a
130    True
131
132    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
133    ... else: a < b
134    Traceback (most recent call last):
135    TypeError...
136    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
137    ... else: a > b
138    Traceback (most recent call last):
139    TypeError...
140    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
141    ... else: a <= b
142    Traceback (most recent call last):
143    TypeError...
144    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
145    ... else: a >= b
146    Traceback (most recent call last):
147    TypeError...
148
149    #>>> print(a.__eq__.__doc__)
150    #EQ
151    >>> print(a.__ne__.__doc__)
152    NE
153    """
154    def __ne__(self, other):
155        """NE"""
156        assert 1 <= self.x <= 2
157        assert isinstance(self, ClassEqNe), type(self)
158        if isinstance(other, X):
159            return self.x != x_of(other)
160        elif isinstance(other, int):
161            return self.x < other
162        return NotImplemented
163
164
165@cython.cclass
166class ClassEqNeGe(ClassEqNe):
167    """
168    >>> a = ClassEqNeGe(1)
169    >>> b = ClassEqNeGe(2)
170    >>> c = ClassEqNeGe(1)
171    >>> a == a
172    True
173    >>> a != a
174    False
175    >>> a >= a
176    True
177    >>> a <= a
178    True
179
180    >>> a == b
181    False
182    >>> a != b
183    True
184    >>> a >= b
185    False
186    >>> b <= a
187    False
188
189    >>> a == c
190    True
191    >>> a != c
192    False
193    >>> a >= c
194    True
195    >>> c <= a
196    True
197
198    >>> b == c
199    False
200    >>> b != c
201    True
202    >>> b >= c
203    True
204    >>> c <= b
205    True
206
207    >>> c == a
208    True
209    >>> c != a
210    False
211    >>> c >= a
212    True
213    >>> a <= c
214    True
215
216    >>> b == a
217    False
218    >>> b != a
219    True
220    >>> b >= a
221    True
222    >>> a <= b
223    True
224
225    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
226    ... else: a < b
227    Traceback (most recent call last):
228    TypeError...
229    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
230    ... else: a > b
231    Traceback (most recent call last):
232    TypeError...
233
234    >>> 2 <= a
235    False
236    >>> a >= 2
237    False
238    >>> 1 <= a
239    True
240    >>> a >= 1
241    True
242    >>> a >= 2
243    False
244
245    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
246    ... else: 'x' <= a
247    Traceback (most recent call last):
248    TypeError...
249    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
250    ... else: a >= 'x'
251    Traceback (most recent call last):
252    TypeError...
253
254    #>>> print(a.__eq__.__doc__)
255    #EQ
256    #>>> print(a.__ne__.__doc__)
257    #NE
258    >>> print(a.__ge__.__doc__)
259    GE
260   """
261    def __ge__(self, other):
262        """GE"""
263        assert 1 <= self.x <= 2
264        assert isinstance(self, ClassEqNeGe), type(self)
265        if isinstance(other, X):
266            return self.x >= x_of(other)
267        elif isinstance(other, int):
268            return self.x >= other
269        return NotImplemented
270
271
272@cython.cclass
273class ClassRichcmpOverride(ClassEqNeGe):
274    """
275    >>> a = ClassRichcmpOverride(1)
276    >>> b = ClassRichcmpOverride(1)
277
278    >>> a == a
279    True
280    >>> a != a
281    False
282
283    >>> a != b if compiled else a == b  # Python ignores __richcmp__()
284    True
285    >>> a == b if compiled else a != b  # Python ignores __richcmp__()
286    False
287
288    >>> if IS_PY2 or not compiled: raise TypeError  # doctest: +ELLIPSIS
289    ... else: a >= b  # should no longer work when __richcmp__ is overwritten
290    Traceback (most recent call last):
291    TypeError...
292    """
293    def __richcmp__(self, other, op):
294        return NotImplemented
295
296
297@cython.cclass
298class ClassLe(X):
299    """
300    >>> a = ClassLe(1)
301    >>> b = ClassLe(2)
302    >>> c = ClassLe(1)
303
304    >>> a <= b
305    True
306    >>> b >= a
307    True
308    >>> b <= a
309    False
310    >>> a >= b
311    False
312
313    >>> a <= c
314    True
315    >>> c >= a
316    True
317    >>> c <= a
318    True
319    >>> a >= c
320    True
321
322    >>> b <= c
323    False
324    >>> c >= b
325    False
326    >>> c <= b
327    True
328    >>> b >= c
329    True
330
331    >>> 2 >= a
332    True
333    >>> a <= 2
334    True
335    >>> 1 >= a
336    True
337    >>> a <= 1
338    True
339    >>> a <= 0
340    False
341
342    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
343    ... else: 'x' >= a
344    Traceback (most recent call last):
345    TypeError...
346    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
347    ... else: a <= 'x'
348    Traceback (most recent call last):
349    TypeError...
350    """
351    def __le__(self, other):
352        assert 1 <= self.x <= 2
353        assert isinstance(self, ClassLe), type(self)
354        if isinstance(other, X):
355            return self.x <= x_of(other)
356        elif isinstance(other, int):
357            return self.x <= other
358        return NotImplemented
359
360
361@cython.cclass
362class ClassLt(X):
363    """
364    >>> a = ClassLt(1)
365    >>> b = ClassLt(2)
366    >>> c = ClassLt(1)
367
368    >>> a < b
369    True
370    >>> b > a
371    True
372    >>> b < a
373    False
374    >>> a > b
375    False
376
377    >>> a < c
378    False
379    >>> c > a
380    False
381    >>> c < a
382    False
383    >>> a > c
384    False
385
386    >>> b < c
387    False
388    >>> c > b
389    False
390    >>> c < b
391    True
392    >>> b > c
393    True
394
395    >>> sorted([a, b, c])
396    [<1>, <1>, <2>]
397    >>> sorted([b, a, c])
398    [<1>, <1>, <2>]
399
400    >>> 2 > a
401    True
402    >>> a < 2
403    True
404    >>> 1 > a
405    False
406    >>> a < 1
407    False
408
409    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
410    ... else: 1 < a
411    Traceback (most recent call last):
412    TypeError...
413
414    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
415    ... else: 'x' > a
416    Traceback (most recent call last):
417    TypeError...
418    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
419    ... else: a < 'x'
420    Traceback (most recent call last):
421    TypeError...
422    """
423    def __lt__(self, other):
424        assert 1 <= self.x <= 2
425        assert isinstance(self, ClassLt), type(self)
426        if isinstance(other, X):
427            return self.x < x_of(other)
428        elif isinstance(other, int):
429            return self.x < other
430        return NotImplemented
431
432
433@cython.cclass
434class ClassLtGtInherited(X):
435    """
436    >>> a = ClassLtGtInherited(1)
437    >>> b = ClassLtGtInherited(2)
438    >>> c = ClassLtGtInherited(1)
439
440    >>> a < b
441    True
442    >>> b > a
443    True
444    >>> b < a
445    False
446    >>> a > b
447    False
448
449    >>> a < c
450    False
451    >>> c > a
452    False
453    >>> c < a
454    False
455    >>> a > c
456    False
457
458    >>> b < c
459    False
460    >>> c > b
461    False
462    >>> c < b
463    True
464    >>> b > c
465    True
466
467    >>> sorted([a, b, c])
468    [<1>, <1>, <2>]
469    >>> sorted([b, a, c])
470    [<1>, <1>, <2>]
471    """
472    def __gt__(self, other):
473        assert 1 <= self.x <= 2
474        assert isinstance(self, ClassLtGtInherited), type(self)
475        if isinstance(other, X):
476            return self.x > x_of(other)
477        elif isinstance(other, int):
478            return self.x > other
479        return NotImplemented
480
481
482@cython.cclass
483class ClassLtGt(X):
484    """
485    >>> a = ClassLtGt(1)
486    >>> b = ClassLtGt(2)
487    >>> c = ClassLtGt(1)
488
489    >>> a < b
490    True
491    >>> b > a
492    True
493    >>> b < a
494    False
495    >>> a > b
496    False
497
498    >>> a < c
499    False
500    >>> c > a
501    False
502    >>> c < a
503    False
504    >>> a > c
505    False
506
507    >>> b < c
508    False
509    >>> c > b
510    False
511    >>> c < b
512    True
513    >>> b > c
514    True
515
516    >>> sorted([a, b, c])
517    [<1>, <1>, <2>]
518    >>> sorted([b, a, c])
519    [<1>, <1>, <2>]
520
521    >>> 2 > a
522    True
523    >>> 2 < a
524    False
525    >>> a < 2
526    True
527    >>> a > 2
528    False
529
530    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
531    ... else: 'x' > a
532    Traceback (most recent call last):
533    TypeError...
534    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
535    ... else: 'x' < a
536    Traceback (most recent call last):
537    TypeError...
538    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
539    ... else: a < 'x'
540    Traceback (most recent call last):
541    TypeError...
542    >>> if IS_PY2: raise TypeError  # doctest: +ELLIPSIS
543    ... else: a > 'x'
544    Traceback (most recent call last):
545    TypeError...
546    """
547    def __lt__(self, other):
548        assert 1 <= self.x <= 2
549        assert isinstance(self, ClassLtGt), type(self)
550        if isinstance(other, X):
551            return self.x < x_of(other)
552        elif isinstance(other, int):
553            return self.x < other
554        return NotImplemented
555
556    def __gt__(self, other):
557        assert 1 <= self.x <= 2
558        assert isinstance(self, ClassLtGt), type(self)
559        if isinstance(other, X):
560            return self.x > x_of(other)
561        elif isinstance(other, int):
562            return self.x > other
563        return NotImplemented
564
565
566@cython.cclass
567class List(list):
568    """
569    >>> l = [1, 2, 3, 4]
570    >>> notl = List(l)
571    >>> notl == l
572    False
573    >>> notl != l     # implemented by base type
574    False
575    >>> notl == notl
576    True
577    >>> notl != notl  # implemented by base type
578    False
579    """
580    def __eq__(self, other):
581        return self is other or list(self) != list(other)
582