3 from test
.test_support
import run_unittest
, TestFailed
, check_warnings
5 # Fake a number that implements numeric methods through __coerce__
7 def __init__(self
, arg
):
11 return '<CoerceNumber %s>' % repr(self
.arg
)
13 def __coerce__(self
, other
):
14 if isinstance(other
, CoerceNumber
):
15 return self
.arg
, other
.arg
17 return (self
.arg
, other
)
19 # New-style class version of CoerceNumber
20 class CoerceTo(object):
21 def __init__(self
, arg
):
23 def __coerce__(self
, other
):
24 if isinstance(other
, CoerceTo
):
25 return self
.arg
, other
.arg
27 return self
.arg
, other
30 # Fake a number that implements numeric ops through methods.
32 def __init__(self
,arg
):
36 return '<MethodNumber %s>' % repr(self
.arg
)
38 def __add__(self
,other
):
39 return self
.arg
+ other
41 def __radd__(self
,other
):
42 return other
+ self
.arg
44 def __sub__(self
,other
):
45 return self
.arg
- other
47 def __rsub__(self
,other
):
48 return other
- self
.arg
50 def __mul__(self
,other
):
51 return self
.arg
* other
53 def __rmul__(self
,other
):
54 return other
* self
.arg
56 def __div__(self
,other
):
57 return self
.arg
/ other
59 def __rdiv__(self
,other
):
60 return other
/ self
.arg
62 def __truediv__(self
,other
):
63 return self
.arg
/ other
65 def __rtruediv__(self
,other
):
66 return other
/ self
.arg
68 def __floordiv__(self
,other
):
69 return self
.arg
// other
71 def __rfloordiv__(self
,other
):
72 return other
// self
.arg
74 def __pow__(self
,other
):
75 return self
.arg
** other
77 def __rpow__(self
,other
):
78 return other
** self
.arg
80 def __mod__(self
,other
):
81 return self
.arg
% other
83 def __rmod__(self
,other
):
84 return other
% self
.arg
86 def __cmp__(self
, other
):
87 return cmp(self
.arg
, other
)
90 candidates
= [2, 2L, 4.0, 2+0j
, [1], (2,), None,
91 MethodNumber(2), CoerceNumber(2)]
93 infix_binops
= [ '+', '-', '*', '**', '%', '//', '/' ]
96 # b = both normal and augmented give same result list
97 # s = single result lists for normal and augmented
98 # e = equals other results
99 # result lists: ['+', '-', '*', '**', '%', '//', ('classic /', 'new /')]
100 # ^^^^^^^^^^^^^^^^^^^^^^
101 # 2-tuple if results differ
102 # else only one value
105 (0,0): ('b', [4, 0, 4, 4, 0, 1, (1, 1.0)]),
107 (0,2): ('b', [6.0, -2.0, 8.0, 16.0, 2.0, 0.0, 0.5]),
108 (0,3): ('b', [4+0j
, 0+0j
, 4+0j
, 4+0j
, 0+0j
, 1+0j
, 1+0j
]),
109 (0,4): ('b', [TE
, TE
, [1, 1], TE
, TE
, TE
, TE
]),
110 (0,5): ('b', [TE
, TE
, (2, 2), TE
, TE
, TE
, TE
]),
111 (0,6): ('b', [TE
, TE
, TE
, TE
, TE
, TE
, TE
]),
127 (2,0): ('b', [6.0, 2.0, 8.0, 16.0, 0.0, 2.0, 2.0]),
129 (2,2): ('b', [8.0, 0.0, 16.0, 256.0, 0.0, 1.0, 1.0]),
130 (2,3): ('b', [6+0j
, 2+0j
, 8+0j
, 16+0j
, 0+0j
, 2+0j
, 2+0j
]),
131 (2,4): ('b', [TE
, TE
, TE
, TE
, TE
, TE
, TE
]),
138 (3,0): ('b', [4+0j
, 0+0j
, 4+0j
, 4+0j
, 0+0j
, 1+0j
, 1+0j
]),
140 (3,2): ('b', [6+0j
, -2+0j
, 8+0j
, 16+0j
, 2+0j
, 0+0j
, 0.5+0j
]),
141 (3,3): ('b', [4+0j
, 0+0j
, 4+0j
, 4+0j
, 0+0j
, 1+0j
, 1+0j
]),
142 (3,4): ('b', [TE
, TE
, TE
, TE
, TE
, TE
, TE
]),
149 (4,0): ('b', [TE
, TE
, [1, 1], TE
, TE
, TE
, TE
]),
151 (4,2): ('b', [TE
, TE
, TE
, TE
, TE
, TE
, TE
]),
152 (4,3): ('b', [TE
, TE
, TE
, TE
, TE
, TE
, TE
]),
153 (4,4): ('b', [[1, 1], TE
, TE
, TE
, TE
, TE
, TE
]),
154 (4,5): ('s', [TE
, TE
, TE
, TE
, TE
, TE
, TE
], [[1, 2], TE
, TE
, TE
, TE
, TE
, TE
]),
155 (4,6): ('b', [TE
, TE
, TE
, TE
, TE
, TE
, TE
]),
160 (5,0): ('b', [TE
, TE
, (2, 2), TE
, TE
, TE
, TE
]),
162 (5,2): ('b', [TE
, TE
, TE
, TE
, TE
, TE
, TE
]),
165 (5,5): ('b', [(2, 2), TE
, TE
, TE
, TE
, TE
, TE
]),
166 (5,6): ('b', [TE
, TE
, TE
, TE
, TE
, TE
, TE
]),
171 (6,0): ('b', [TE
, TE
, TE
, TE
, TE
, TE
, TE
]),
204 def process_infix_results():
205 for key
in sorted(infix_results
):
206 val
= infix_results
[key
]
208 infix_results
[key
] = infix_results
[val
[1]]
211 res
= (val
[1], val
[2])
213 res
= (val
[1], val
[1])
215 if isinstance(res
[i
][6], tuple):
217 # testing with classic (floor) division
218 res
[i
][6] = res
[i
][6][0]
221 res
[i
][6] = res
[i
][6][1]
222 infix_results
[key
] = res
225 prefix_binops
= [ 'divmod' ]
227 [(1,0), (1L,0L), (0.0,2.0), ((1+0j
),0j
), TE
, TE
, TE
, TE
, (1,0)],
228 [(1L,0L), (1L,0L), (0.0,2.0), ((1+0j
),0j
), TE
, TE
, TE
, TE
, (1L,0L)],
229 [(2.0,0.0), (2.0,0.0), (1.0,0.0), ((2+0j
),0j
), TE
, TE
, TE
, TE
, (2.0,0.0)],
230 [((1+0j
),0j
), ((1+0j
),0j
), (0j
,(2+0j
)), ((1+0j
),0j
), TE
, TE
, TE
, TE
, ((1+0j
),0j
)],
231 [TE
, TE
, TE
, TE
, TE
, TE
, TE
, TE
, TE
],
232 [TE
, TE
, TE
, TE
, TE
, TE
, TE
, TE
, TE
],
233 [TE
, TE
, TE
, TE
, TE
, TE
, TE
, TE
, TE
],
234 [TE
, TE
, TE
, TE
, TE
, TE
, TE
, TE
, TE
],
235 [(1,0), (1L,0L), (0.0,2.0), ((1+0j
),0j
), TE
, TE
, TE
, TE
, (1,0)]
238 def format_float(value
):
239 if abs(value
) < 0.01:
242 return '%.1f' % value
244 # avoid testing platform fp quirks
245 def format_result(value
):
246 if isinstance(value
, complex):
247 return '(%s + %sj)' % (format_float(value
.real
),
248 format_float(value
.imag
))
249 elif isinstance(value
, float):
250 return format_float(value
)
253 class CoercionTest(unittest
.TestCase
):
254 def test_infix_binops(self
):
255 for ia
, a
in enumerate(candidates
):
256 for ib
, b
in enumerate(candidates
):
257 results
= infix_results
[(ia
, ib
)]
258 for op
, res
, ires
in zip(infix_binops
, results
[0], results
[1]):
260 self
.assertRaises(TypeError, eval,
261 'a %s b' % op
, {'a': a
, 'b': b
})
263 self
.assertEquals(format_result(res
),
264 format_result(eval('a %s b' % op
)),
265 '%s %s %s == %s failed' % (a
, op
, b
, res
))
269 z
= a
# assume it has no inplace ops
276 self
.fail("TypeError not raised")
279 self
.assertEquals(ires
, z
)
281 def test_prefix_binops(self
):
282 for ia
, a
in enumerate(candidates
):
283 for ib
, b
in enumerate(candidates
):
284 for op
in prefix_binops
:
285 res
= prefix_results
[ia
][ib
]
287 self
.assertRaises(TypeError, eval,
288 '%s(a, b)' % op
, {'a': a
, 'b': b
})
290 self
.assertEquals(format_result(res
),
291 format_result(eval('%s(a, b)' % op
)),
292 '%s(%s, %s) == %s failed' % (op
, a
, b
, res
))
294 def test_cmptypes(self
):
295 # Built-in tp_compare slots expect their arguments to have the
296 # same type, but a user-defined __coerce__ doesn't have to obey.
298 evil_coercer
= CoerceTo(42)
299 # Make sure these don't crash any more
300 self
.assertNotEquals(cmp(u
'fish', evil_coercer
), 0)
301 self
.assertNotEquals(cmp(slice(1), evil_coercer
), 0)
302 # ...but that this still works
303 class WackyComparer(object):
304 def __cmp__(slf
, other
):
305 self
.assertTrue(other
== 42, 'expected evil_coercer, got %r' % other
)
307 __hash__
= None # Invalid cmp makes this unhashable
308 self
.assertEquals(cmp(WackyComparer(), evil_coercer
), 0)
309 # ...and classic classes too, since that code path is a little different
310 class ClassicWackyComparer
:
311 def __cmp__(slf
, other
):
312 self
.assertTrue(other
== 42, 'expected evil_coercer, got %r' % other
)
314 self
.assertEquals(cmp(ClassicWackyComparer(), evil_coercer
), 0)
316 def test_infinite_rec_classic_classes(self
):
317 # if __coerce__() returns its arguments reversed it causes an infinite
318 # recursion for classic classes.
320 def __coerce__(self
, other
):
323 exc
= TestFailed("__coerce__() returning its arguments reverse "
324 "should raise RuntimeError")
327 except (RuntimeError, TypeError):
335 with
check_warnings(("complex divmod.., // and % are deprecated",
337 ("classic (int|long) division", DeprecationWarning),
339 process_infix_results()
340 # now infix_results has two lists of results for every pairing.
342 run_unittest(CoercionTest
)
344 if __name__
== "__main__":