python (3.12.0)
1 """Tests for Lib/fractions.py."""
2
3 from decimal import Decimal
4 from test.support import requires_IEEE_754
5 import math
6 import numbers
7 import operator
8 import fractions
9 import functools
10 import sys
11 import typing
12 import unittest
13 from copy import copy, deepcopy
14 import pickle
15 from pickle import dumps, loads
16 F = fractions.Fraction
17
18
19 class ESC[4;38;5;81mDummyFloat(ESC[4;38;5;149mobject):
20 """Dummy float class for testing comparisons with Fractions"""
21
22 def __init__(self, value):
23 if not isinstance(value, float):
24 raise TypeError("DummyFloat can only be initialized from float")
25 self.value = value
26
27 def _richcmp(self, other, op):
28 if isinstance(other, numbers.Rational):
29 return op(F.from_float(self.value), other)
30 elif isinstance(other, DummyFloat):
31 return op(self.value, other.value)
32 else:
33 return NotImplemented
34
35 def __eq__(self, other): return self._richcmp(other, operator.eq)
36 def __le__(self, other): return self._richcmp(other, operator.le)
37 def __lt__(self, other): return self._richcmp(other, operator.lt)
38 def __ge__(self, other): return self._richcmp(other, operator.ge)
39 def __gt__(self, other): return self._richcmp(other, operator.gt)
40
41 # shouldn't be calling __float__ at all when doing comparisons
42 def __float__(self):
43 assert False, "__float__ should not be invoked for comparisons"
44
45 # same goes for subtraction
46 def __sub__(self, other):
47 assert False, "__sub__ should not be invoked for comparisons"
48 __rsub__ = __sub__
49
50
51 class ESC[4;38;5;81mDummyRational(ESC[4;38;5;149mobject):
52 """Test comparison of Fraction with a naive rational implementation."""
53
54 def __init__(self, num, den):
55 g = math.gcd(num, den)
56 self.num = num // g
57 self.den = den // g
58
59 def __eq__(self, other):
60 if isinstance(other, fractions.Fraction):
61 return (self.num == other._numerator and
62 self.den == other._denominator)
63 else:
64 return NotImplemented
65
66 def __lt__(self, other):
67 return(self.num * other._denominator < self.den * other._numerator)
68
69 def __gt__(self, other):
70 return(self.num * other._denominator > self.den * other._numerator)
71
72 def __le__(self, other):
73 return(self.num * other._denominator <= self.den * other._numerator)
74
75 def __ge__(self, other):
76 return(self.num * other._denominator >= self.den * other._numerator)
77
78 # this class is for testing comparisons; conversion to float
79 # should never be used for a comparison, since it loses accuracy
80 def __float__(self):
81 assert False, "__float__ should not be invoked"
82
83 class ESC[4;38;5;81mDummyFraction(ESC[4;38;5;149mfractionsESC[4;38;5;149m.ESC[4;38;5;149mFraction):
84 """Dummy Fraction subclass for copy and deepcopy testing."""
85
86
87 def _components(r):
88 return (r.numerator, r.denominator)
89
90
91 class ESC[4;38;5;81mFractionTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
92
93 def assertTypedEquals(self, expected, actual):
94 """Asserts that both the types and values are the same."""
95 self.assertEqual(type(expected), type(actual))
96 self.assertEqual(expected, actual)
97
98 def assertTypedTupleEquals(self, expected, actual):
99 """Asserts that both the types and values in the tuples are the same."""
100 self.assertTupleEqual(expected, actual)
101 self.assertListEqual(list(map(type, expected)), list(map(type, actual)))
102
103 def assertRaisesMessage(self, exc_type, message,
104 callable, *args, **kwargs):
105 """Asserts that callable(*args, **kwargs) raises exc_type(message)."""
106 try:
107 callable(*args, **kwargs)
108 except exc_type as e:
109 self.assertEqual(message, str(e))
110 else:
111 self.fail("%s not raised" % exc_type.__name__)
112
113 def testInit(self):
114 self.assertEqual((0, 1), _components(F()))
115 self.assertEqual((7, 1), _components(F(7)))
116 self.assertEqual((7, 3), _components(F(F(7, 3))))
117
118 self.assertEqual((-1, 1), _components(F(-1, 1)))
119 self.assertEqual((-1, 1), _components(F(1, -1)))
120 self.assertEqual((1, 1), _components(F(-2, -2)))
121 self.assertEqual((1, 2), _components(F(5, 10)))
122 self.assertEqual((7, 15), _components(F(7, 15)))
123 self.assertEqual((10**23, 1), _components(F(10**23)))
124
125 self.assertEqual((3, 77), _components(F(F(3, 7), 11)))
126 self.assertEqual((-9, 5), _components(F(2, F(-10, 9))))
127 self.assertEqual((2486, 2485), _components(F(F(22, 7), F(355, 113))))
128
129 self.assertRaisesMessage(ZeroDivisionError, "Fraction(12, 0)",
130 F, 12, 0)
131 self.assertRaises(TypeError, F, 1.5 + 3j)
132
133 self.assertRaises(TypeError, F, "3/2", 3)
134 self.assertRaises(TypeError, F, 3, 0j)
135 self.assertRaises(TypeError, F, 3, 1j)
136 self.assertRaises(TypeError, F, 1, 2, 3)
137
138 @requires_IEEE_754
139 def testInitFromFloat(self):
140 self.assertEqual((5, 2), _components(F(2.5)))
141 self.assertEqual((0, 1), _components(F(-0.0)))
142 self.assertEqual((3602879701896397, 36028797018963968),
143 _components(F(0.1)))
144 # bug 16469: error types should be consistent with float -> int
145 self.assertRaises(ValueError, F, float('nan'))
146 self.assertRaises(OverflowError, F, float('inf'))
147 self.assertRaises(OverflowError, F, float('-inf'))
148
149 def testInitFromDecimal(self):
150 self.assertEqual((11, 10),
151 _components(F(Decimal('1.1'))))
152 self.assertEqual((7, 200),
153 _components(F(Decimal('3.5e-2'))))
154 self.assertEqual((0, 1),
155 _components(F(Decimal('.000e20'))))
156 # bug 16469: error types should be consistent with decimal -> int
157 self.assertRaises(ValueError, F, Decimal('nan'))
158 self.assertRaises(ValueError, F, Decimal('snan'))
159 self.assertRaises(OverflowError, F, Decimal('inf'))
160 self.assertRaises(OverflowError, F, Decimal('-inf'))
161
162 def testFromString(self):
163 self.assertEqual((5, 1), _components(F("5")))
164 self.assertEqual((3, 2), _components(F("3/2")))
165 self.assertEqual((3, 2), _components(F("3 / 2")))
166 self.assertEqual((3, 2), _components(F(" \n +3/2")))
167 self.assertEqual((-3, 2), _components(F("-3/2 ")))
168 self.assertEqual((13, 2), _components(F(" 013/02 \n ")))
169 self.assertEqual((16, 5), _components(F(" 3.2 ")))
170 self.assertEqual((-16, 5), _components(F(" -3.2 ")))
171 self.assertEqual((-3, 1), _components(F(" -3. ")))
172 self.assertEqual((3, 5), _components(F(" .6 ")))
173 self.assertEqual((1, 3125), _components(F("32.e-5")))
174 self.assertEqual((1000000, 1), _components(F("1E+06")))
175 self.assertEqual((-12300, 1), _components(F("-1.23e4")))
176 self.assertEqual((0, 1), _components(F(" .0e+0\t")))
177 self.assertEqual((0, 1), _components(F("-0.000e0")))
178 self.assertEqual((123, 1), _components(F("1_2_3")))
179 self.assertEqual((41, 107), _components(F("1_2_3/3_2_1")))
180 self.assertEqual((6283, 2000), _components(F("3.14_15")))
181 self.assertEqual((6283, 2*10**13), _components(F("3.14_15e-1_0")))
182 self.assertEqual((101, 100), _components(F("1.01")))
183 self.assertEqual((101, 100), _components(F("1.0_1")))
184
185 self.assertRaisesMessage(
186 ZeroDivisionError, "Fraction(3, 0)",
187 F, "3/0")
188 self.assertRaisesMessage(
189 ValueError, "Invalid literal for Fraction: '3/'",
190 F, "3/")
191 self.assertRaisesMessage(
192 ValueError, "Invalid literal for Fraction: '/2'",
193 F, "/2")
194 self.assertRaisesMessage(
195 # Denominators don't need a sign.
196 ValueError, "Invalid literal for Fraction: '3/+2'",
197 F, "3/+2")
198 self.assertRaisesMessage(
199 # Imitate float's parsing.
200 ValueError, "Invalid literal for Fraction: '+ 3/2'",
201 F, "+ 3/2")
202 self.assertRaisesMessage(
203 # Avoid treating '.' as a regex special character.
204 ValueError, "Invalid literal for Fraction: '3a2'",
205 F, "3a2")
206 self.assertRaisesMessage(
207 # Don't accept combinations of decimals and rationals.
208 ValueError, "Invalid literal for Fraction: '3/7.2'",
209 F, "3/7.2")
210 self.assertRaisesMessage(
211 # Don't accept combinations of decimals and rationals.
212 ValueError, "Invalid literal for Fraction: '3.2/7'",
213 F, "3.2/7")
214 self.assertRaisesMessage(
215 # Allow 3. and .3, but not .
216 ValueError, "Invalid literal for Fraction: '.'",
217 F, ".")
218 self.assertRaisesMessage(
219 ValueError, "Invalid literal for Fraction: '_'",
220 F, "_")
221 self.assertRaisesMessage(
222 ValueError, "Invalid literal for Fraction: '_1'",
223 F, "_1")
224 self.assertRaisesMessage(
225 ValueError, "Invalid literal for Fraction: '1__2'",
226 F, "1__2")
227 self.assertRaisesMessage(
228 ValueError, "Invalid literal for Fraction: '/_'",
229 F, "/_")
230 self.assertRaisesMessage(
231 ValueError, "Invalid literal for Fraction: '1_/'",
232 F, "1_/")
233 self.assertRaisesMessage(
234 ValueError, "Invalid literal for Fraction: '_1/'",
235 F, "_1/")
236 self.assertRaisesMessage(
237 ValueError, "Invalid literal for Fraction: '1__2/'",
238 F, "1__2/")
239 self.assertRaisesMessage(
240 ValueError, "Invalid literal for Fraction: '1/_'",
241 F, "1/_")
242 self.assertRaisesMessage(
243 ValueError, "Invalid literal for Fraction: '1/_1'",
244 F, "1/_1")
245 self.assertRaisesMessage(
246 ValueError, "Invalid literal for Fraction: '1/1__2'",
247 F, "1/1__2")
248 self.assertRaisesMessage(
249 ValueError, "Invalid literal for Fraction: '1._111'",
250 F, "1._111")
251 self.assertRaisesMessage(
252 ValueError, "Invalid literal for Fraction: '1.1__1'",
253 F, "1.1__1")
254 self.assertRaisesMessage(
255 ValueError, "Invalid literal for Fraction: '1.1e+_1'",
256 F, "1.1e+_1")
257 self.assertRaisesMessage(
258 ValueError, "Invalid literal for Fraction: '1.1e+1__1'",
259 F, "1.1e+1__1")
260 # Test catastrophic backtracking.
261 val = "9"*50 + "_"
262 self.assertRaisesMessage(
263 ValueError, "Invalid literal for Fraction: '" + val + "'",
264 F, val)
265 self.assertRaisesMessage(
266 ValueError, "Invalid literal for Fraction: '1/" + val + "'",
267 F, "1/" + val)
268 self.assertRaisesMessage(
269 ValueError, "Invalid literal for Fraction: '1." + val + "'",
270 F, "1." + val)
271 self.assertRaisesMessage(
272 ValueError, "Invalid literal for Fraction: '1.1+e" + val + "'",
273 F, "1.1+e" + val)
274
275 def testImmutable(self):
276 r = F(7, 3)
277 r.__init__(2, 15)
278 self.assertEqual((7, 3), _components(r))
279
280 self.assertRaises(AttributeError, setattr, r, 'numerator', 12)
281 self.assertRaises(AttributeError, setattr, r, 'denominator', 6)
282 self.assertEqual((7, 3), _components(r))
283
284 # But if you _really_ need to:
285 r._numerator = 4
286 r._denominator = 2
287 self.assertEqual((4, 2), _components(r))
288 # Which breaks some important operations:
289 self.assertNotEqual(F(4, 2), r)
290
291 def testFromFloat(self):
292 self.assertRaises(TypeError, F.from_float, 3+4j)
293 self.assertEqual((10, 1), _components(F.from_float(10)))
294 bigint = 1234567890123456789
295 self.assertEqual((bigint, 1), _components(F.from_float(bigint)))
296 self.assertEqual((0, 1), _components(F.from_float(-0.0)))
297 self.assertEqual((10, 1), _components(F.from_float(10.0)))
298 self.assertEqual((-5, 2), _components(F.from_float(-2.5)))
299 self.assertEqual((99999999999999991611392, 1),
300 _components(F.from_float(1e23)))
301 self.assertEqual(float(10**23), float(F.from_float(1e23)))
302 self.assertEqual((3602879701896397, 1125899906842624),
303 _components(F.from_float(3.2)))
304 self.assertEqual(3.2, float(F.from_float(3.2)))
305
306 inf = 1e1000
307 nan = inf - inf
308 # bug 16469: error types should be consistent with float -> int
309 self.assertRaisesMessage(
310 OverflowError, "cannot convert Infinity to integer ratio",
311 F.from_float, inf)
312 self.assertRaisesMessage(
313 OverflowError, "cannot convert Infinity to integer ratio",
314 F.from_float, -inf)
315 self.assertRaisesMessage(
316 ValueError, "cannot convert NaN to integer ratio",
317 F.from_float, nan)
318
319 def testFromDecimal(self):
320 self.assertRaises(TypeError, F.from_decimal, 3+4j)
321 self.assertEqual(F(10, 1), F.from_decimal(10))
322 self.assertEqual(F(0), F.from_decimal(Decimal("-0")))
323 self.assertEqual(F(5, 10), F.from_decimal(Decimal("0.5")))
324 self.assertEqual(F(5, 1000), F.from_decimal(Decimal("5e-3")))
325 self.assertEqual(F(5000), F.from_decimal(Decimal("5e3")))
326 self.assertEqual(1 - F(1, 10**30),
327 F.from_decimal(Decimal("0." + "9" * 30)))
328
329 # bug 16469: error types should be consistent with decimal -> int
330 self.assertRaisesMessage(
331 OverflowError, "cannot convert Infinity to integer ratio",
332 F.from_decimal, Decimal("inf"))
333 self.assertRaisesMessage(
334 OverflowError, "cannot convert Infinity to integer ratio",
335 F.from_decimal, Decimal("-inf"))
336 self.assertRaisesMessage(
337 ValueError, "cannot convert NaN to integer ratio",
338 F.from_decimal, Decimal("nan"))
339 self.assertRaisesMessage(
340 ValueError, "cannot convert NaN to integer ratio",
341 F.from_decimal, Decimal("snan"))
342
343 def test_is_integer(self):
344 self.assertTrue(F(1, 1).is_integer())
345 self.assertTrue(F(-1, 1).is_integer())
346 self.assertTrue(F(1, -1).is_integer())
347 self.assertTrue(F(2, 2).is_integer())
348 self.assertTrue(F(-2, 2).is_integer())
349 self.assertTrue(F(2, -2).is_integer())
350
351 self.assertFalse(F(1, 2).is_integer())
352 self.assertFalse(F(-1, 2).is_integer())
353 self.assertFalse(F(1, -2).is_integer())
354 self.assertFalse(F(-1, -2).is_integer())
355
356 def test_as_integer_ratio(self):
357 self.assertEqual(F(4, 6).as_integer_ratio(), (2, 3))
358 self.assertEqual(F(-4, 6).as_integer_ratio(), (-2, 3))
359 self.assertEqual(F(4, -6).as_integer_ratio(), (-2, 3))
360 self.assertEqual(F(0, 6).as_integer_ratio(), (0, 1))
361
362 def testLimitDenominator(self):
363 rpi = F('3.1415926535897932')
364 self.assertEqual(rpi.limit_denominator(10000), F(355, 113))
365 self.assertEqual(-rpi.limit_denominator(10000), F(-355, 113))
366 self.assertEqual(rpi.limit_denominator(113), F(355, 113))
367 self.assertEqual(rpi.limit_denominator(112), F(333, 106))
368 self.assertEqual(F(201, 200).limit_denominator(100), F(1))
369 self.assertEqual(F(201, 200).limit_denominator(101), F(102, 101))
370 self.assertEqual(F(0).limit_denominator(10000), F(0))
371 for i in (0, -1):
372 self.assertRaisesMessage(
373 ValueError, "max_denominator should be at least 1",
374 F(1).limit_denominator, i)
375
376 def testConversions(self):
377 self.assertTypedEquals(-1, math.trunc(F(-11, 10)))
378 self.assertTypedEquals(1, math.trunc(F(11, 10)))
379 self.assertTypedEquals(-2, math.floor(F(-11, 10)))
380 self.assertTypedEquals(-1, math.ceil(F(-11, 10)))
381 self.assertTypedEquals(-1, math.ceil(F(-10, 10)))
382 self.assertTypedEquals(-1, int(F(-11, 10)))
383 self.assertTypedEquals(0, round(F(-1, 10)))
384 self.assertTypedEquals(0, round(F(-5, 10)))
385 self.assertTypedEquals(-2, round(F(-15, 10)))
386 self.assertTypedEquals(-1, round(F(-7, 10)))
387
388 self.assertEqual(False, bool(F(0, 1)))
389 self.assertEqual(True, bool(F(3, 2)))
390 self.assertTypedEquals(0.1, float(F(1, 10)))
391
392 # Check that __float__ isn't implemented by converting the
393 # numerator and denominator to float before dividing.
394 self.assertRaises(OverflowError, float, int('2'*400+'7'))
395 self.assertAlmostEqual(2.0/3,
396 float(F(int('2'*400+'7'), int('3'*400+'1'))))
397
398 self.assertTypedEquals(0.1+0j, complex(F(1,10)))
399
400 def testSupportsInt(self):
401 # See bpo-44547.
402 f = F(3, 2)
403 self.assertIsInstance(f, typing.SupportsInt)
404 self.assertEqual(int(f), 1)
405 self.assertEqual(type(int(f)), int)
406
407 def testIntGuaranteesIntReturn(self):
408 # Check that int(some_fraction) gives a result of exact type `int`
409 # even if the fraction is using some other Integral type for its
410 # numerator and denominator.
411
412 class ESC[4;38;5;81mCustomInt(ESC[4;38;5;149mint):
413 """
414 Subclass of int with just enough machinery to convince the Fraction
415 constructor to produce something with CustomInt numerator and
416 denominator.
417 """
418
419 @property
420 def numerator(self):
421 return self
422
423 @property
424 def denominator(self):
425 return CustomInt(1)
426
427 def __mul__(self, other):
428 return CustomInt(int(self) * int(other))
429
430 def __floordiv__(self, other):
431 return CustomInt(int(self) // int(other))
432
433 f = F(CustomInt(13), CustomInt(5))
434
435 self.assertIsInstance(f.numerator, CustomInt)
436 self.assertIsInstance(f.denominator, CustomInt)
437 self.assertIsInstance(f, typing.SupportsInt)
438 self.assertEqual(int(f), 2)
439 self.assertEqual(type(int(f)), int)
440
441 def testBoolGuarateesBoolReturn(self):
442 # Ensure that __bool__ is used on numerator which guarantees a bool
443 # return. See also bpo-39274.
444 @functools.total_ordering
445 class ESC[4;38;5;81mCustomValue:
446 denominator = 1
447
448 def __init__(self, value):
449 self.value = value
450
451 def __bool__(self):
452 return bool(self.value)
453
454 @property
455 def numerator(self):
456 # required to preserve `self` during instantiation
457 return self
458
459 def __eq__(self, other):
460 raise AssertionError("Avoid comparisons in Fraction.__bool__")
461
462 __lt__ = __eq__
463
464 # We did not implement all abstract methods, so register:
465 numbers.Rational.register(CustomValue)
466
467 numerator = CustomValue(1)
468 r = F(numerator)
469 # ensure the numerator was not lost during instantiation:
470 self.assertIs(r.numerator, numerator)
471 self.assertIs(bool(r), True)
472
473 numerator = CustomValue(0)
474 r = F(numerator)
475 self.assertIs(bool(r), False)
476
477 def testRound(self):
478 self.assertTypedEquals(F(-200), round(F(-150), -2))
479 self.assertTypedEquals(F(-200), round(F(-250), -2))
480 self.assertTypedEquals(F(30), round(F(26), -1))
481 self.assertTypedEquals(F(-2, 10), round(F(-15, 100), 1))
482 self.assertTypedEquals(F(-2, 10), round(F(-25, 100), 1))
483
484 def testArithmetic(self):
485 self.assertEqual(F(1, 2), F(1, 10) + F(2, 5))
486 self.assertEqual(F(-3, 10), F(1, 10) - F(2, 5))
487 self.assertEqual(F(1, 25), F(1, 10) * F(2, 5))
488 self.assertEqual(F(5, 6), F(2, 3) * F(5, 4))
489 self.assertEqual(F(1, 4), F(1, 10) / F(2, 5))
490 self.assertEqual(F(-15, 8), F(3, 4) / F(-2, 5))
491 self.assertRaises(ZeroDivisionError, operator.truediv, F(1), F(0))
492 self.assertTypedEquals(2, F(9, 10) // F(2, 5))
493 self.assertTypedEquals(10**23, F(10**23, 1) // F(1))
494 self.assertEqual(F(5, 6), F(7, 3) % F(3, 2))
495 self.assertEqual(F(2, 3), F(-7, 3) % F(3, 2))
496 self.assertEqual((F(1), F(5, 6)), divmod(F(7, 3), F(3, 2)))
497 self.assertEqual((F(-2), F(2, 3)), divmod(F(-7, 3), F(3, 2)))
498 self.assertEqual(F(8, 27), F(2, 3) ** F(3))
499 self.assertEqual(F(27, 8), F(2, 3) ** F(-3))
500 self.assertTypedEquals(2.0, F(4) ** F(1, 2))
501 self.assertEqual(F(1, 1), +F(1, 1))
502 z = pow(F(-1), F(1, 2))
503 self.assertAlmostEqual(z.real, 0)
504 self.assertEqual(z.imag, 1)
505 # Regression test for #27539.
506 p = F(-1, 2) ** 0
507 self.assertEqual(p, F(1, 1))
508 self.assertEqual(p.numerator, 1)
509 self.assertEqual(p.denominator, 1)
510 p = F(-1, 2) ** -1
511 self.assertEqual(p, F(-2, 1))
512 self.assertEqual(p.numerator, -2)
513 self.assertEqual(p.denominator, 1)
514 p = F(-1, 2) ** -2
515 self.assertEqual(p, F(4, 1))
516 self.assertEqual(p.numerator, 4)
517 self.assertEqual(p.denominator, 1)
518
519 def testLargeArithmetic(self):
520 self.assertTypedEquals(
521 F(10101010100808080808080808101010101010000000000000000,
522 1010101010101010101010101011111111101010101010101010101010101),
523 F(10**35+1, 10**27+1) % F(10**27+1, 10**35-1)
524 )
525 self.assertTypedEquals(
526 F(7, 1901475900342344102245054808064),
527 F(-2**100, 3) % F(5, 2**100)
528 )
529 self.assertTypedTupleEquals(
530 (9999999999999999,
531 F(10101010100808080808080808101010101010000000000000000,
532 1010101010101010101010101011111111101010101010101010101010101)),
533 divmod(F(10**35+1, 10**27+1), F(10**27+1, 10**35-1))
534 )
535 self.assertTypedEquals(
536 -2 ** 200 // 15,
537 F(-2**100, 3) // F(5, 2**100)
538 )
539 self.assertTypedEquals(
540 1,
541 F(5, 2**100) // F(3, 2**100)
542 )
543 self.assertTypedEquals(
544 (1, F(2, 2**100)),
545 divmod(F(5, 2**100), F(3, 2**100))
546 )
547 self.assertTypedTupleEquals(
548 (-2 ** 200 // 15,
549 F(7, 1901475900342344102245054808064)),
550 divmod(F(-2**100, 3), F(5, 2**100))
551 )
552
553 def testMixedArithmetic(self):
554 self.assertTypedEquals(F(11, 10), F(1, 10) + 1)
555 self.assertTypedEquals(1.1, F(1, 10) + 1.0)
556 self.assertTypedEquals(1.1 + 0j, F(1, 10) + (1.0 + 0j))
557 self.assertTypedEquals(F(11, 10), 1 + F(1, 10))
558 self.assertTypedEquals(1.1, 1.0 + F(1, 10))
559 self.assertTypedEquals(1.1 + 0j, (1.0 + 0j) + F(1, 10))
560
561 self.assertTypedEquals(F(-9, 10), F(1, 10) - 1)
562 self.assertTypedEquals(-0.9, F(1, 10) - 1.0)
563 self.assertTypedEquals(-0.9 + 0j, F(1, 10) - (1.0 + 0j))
564 self.assertTypedEquals(F(9, 10), 1 - F(1, 10))
565 self.assertTypedEquals(0.9, 1.0 - F(1, 10))
566 self.assertTypedEquals(0.9 + 0j, (1.0 + 0j) - F(1, 10))
567
568 self.assertTypedEquals(F(1, 10), F(1, 10) * 1)
569 self.assertTypedEquals(0.1, F(1, 10) * 1.0)
570 self.assertTypedEquals(0.1 + 0j, F(1, 10) * (1.0 + 0j))
571 self.assertTypedEquals(F(1, 10), 1 * F(1, 10))
572 self.assertTypedEquals(0.1, 1.0 * F(1, 10))
573 self.assertTypedEquals(0.1 + 0j, (1.0 + 0j) * F(1, 10))
574
575 self.assertTypedEquals(F(1, 10), F(1, 10) / 1)
576 self.assertTypedEquals(0.1, F(1, 10) / 1.0)
577 self.assertTypedEquals(0.1 + 0j, F(1, 10) / (1.0 + 0j))
578 self.assertTypedEquals(F(10, 1), 1 / F(1, 10))
579 self.assertTypedEquals(10.0, 1.0 / F(1, 10))
580 self.assertTypedEquals(10.0 + 0j, (1.0 + 0j) / F(1, 10))
581
582 self.assertTypedEquals(0, F(1, 10) // 1)
583 self.assertTypedEquals(0.0, F(1, 10) // 1.0)
584 self.assertTypedEquals(10, 1 // F(1, 10))
585 self.assertTypedEquals(10**23, 10**22 // F(1, 10))
586 self.assertTypedEquals(1.0 // 0.1, 1.0 // F(1, 10))
587
588 self.assertTypedEquals(F(1, 10), F(1, 10) % 1)
589 self.assertTypedEquals(0.1, F(1, 10) % 1.0)
590 self.assertTypedEquals(F(0, 1), 1 % F(1, 10))
591 self.assertTypedEquals(1.0 % 0.1, 1.0 % F(1, 10))
592 self.assertTypedEquals(0.1, F(1, 10) % float('inf'))
593 self.assertTypedEquals(float('-inf'), F(1, 10) % float('-inf'))
594 self.assertTypedEquals(float('inf'), F(-1, 10) % float('inf'))
595 self.assertTypedEquals(-0.1, F(-1, 10) % float('-inf'))
596
597 self.assertTypedTupleEquals((0, F(1, 10)), divmod(F(1, 10), 1))
598 self.assertTypedTupleEquals(divmod(0.1, 1.0), divmod(F(1, 10), 1.0))
599 self.assertTypedTupleEquals((10, F(0)), divmod(1, F(1, 10)))
600 self.assertTypedTupleEquals(divmod(1.0, 0.1), divmod(1.0, F(1, 10)))
601 self.assertTypedTupleEquals(divmod(0.1, float('inf')), divmod(F(1, 10), float('inf')))
602 self.assertTypedTupleEquals(divmod(0.1, float('-inf')), divmod(F(1, 10), float('-inf')))
603 self.assertTypedTupleEquals(divmod(-0.1, float('inf')), divmod(F(-1, 10), float('inf')))
604 self.assertTypedTupleEquals(divmod(-0.1, float('-inf')), divmod(F(-1, 10), float('-inf')))
605
606 # ** has more interesting conversion rules.
607 self.assertTypedEquals(F(100, 1), F(1, 10) ** -2)
608 self.assertTypedEquals(F(100, 1), F(10, 1) ** 2)
609 self.assertTypedEquals(0.1, F(1, 10) ** 1.0)
610 self.assertTypedEquals(0.1 + 0j, F(1, 10) ** (1.0 + 0j))
611 self.assertTypedEquals(4 , 2 ** F(2, 1))
612 z = pow(-1, F(1, 2))
613 self.assertAlmostEqual(0, z.real)
614 self.assertEqual(1, z.imag)
615 self.assertTypedEquals(F(1, 4) , 2 ** F(-2, 1))
616 self.assertTypedEquals(2.0 , 4 ** F(1, 2))
617 self.assertTypedEquals(0.25, 2.0 ** F(-2, 1))
618 self.assertTypedEquals(1.0 + 0j, (1.0 + 0j) ** F(1, 10))
619 self.assertRaises(ZeroDivisionError, operator.pow,
620 F(0, 1), -2)
621
622 def testMixingWithDecimal(self):
623 # Decimal refuses mixed arithmetic (but not mixed comparisons)
624 self.assertRaises(TypeError, operator.add,
625 F(3,11), Decimal('3.1415926'))
626 self.assertRaises(TypeError, operator.add,
627 Decimal('3.1415926'), F(3,11))
628
629 def testComparisons(self):
630 self.assertTrue(F(1, 2) < F(2, 3))
631 self.assertFalse(F(1, 2) < F(1, 2))
632 self.assertTrue(F(1, 2) <= F(2, 3))
633 self.assertTrue(F(1, 2) <= F(1, 2))
634 self.assertFalse(F(2, 3) <= F(1, 2))
635 self.assertTrue(F(1, 2) == F(1, 2))
636 self.assertFalse(F(1, 2) == F(1, 3))
637 self.assertFalse(F(1, 2) != F(1, 2))
638 self.assertTrue(F(1, 2) != F(1, 3))
639
640 def testComparisonsDummyRational(self):
641 self.assertTrue(F(1, 2) == DummyRational(1, 2))
642 self.assertTrue(DummyRational(1, 2) == F(1, 2))
643 self.assertFalse(F(1, 2) == DummyRational(3, 4))
644 self.assertFalse(DummyRational(3, 4) == F(1, 2))
645
646 self.assertTrue(F(1, 2) < DummyRational(3, 4))
647 self.assertFalse(F(1, 2) < DummyRational(1, 2))
648 self.assertFalse(F(1, 2) < DummyRational(1, 7))
649 self.assertFalse(F(1, 2) > DummyRational(3, 4))
650 self.assertFalse(F(1, 2) > DummyRational(1, 2))
651 self.assertTrue(F(1, 2) > DummyRational(1, 7))
652 self.assertTrue(F(1, 2) <= DummyRational(3, 4))
653 self.assertTrue(F(1, 2) <= DummyRational(1, 2))
654 self.assertFalse(F(1, 2) <= DummyRational(1, 7))
655 self.assertFalse(F(1, 2) >= DummyRational(3, 4))
656 self.assertTrue(F(1, 2) >= DummyRational(1, 2))
657 self.assertTrue(F(1, 2) >= DummyRational(1, 7))
658
659 self.assertTrue(DummyRational(1, 2) < F(3, 4))
660 self.assertFalse(DummyRational(1, 2) < F(1, 2))
661 self.assertFalse(DummyRational(1, 2) < F(1, 7))
662 self.assertFalse(DummyRational(1, 2) > F(3, 4))
663 self.assertFalse(DummyRational(1, 2) > F(1, 2))
664 self.assertTrue(DummyRational(1, 2) > F(1, 7))
665 self.assertTrue(DummyRational(1, 2) <= F(3, 4))
666 self.assertTrue(DummyRational(1, 2) <= F(1, 2))
667 self.assertFalse(DummyRational(1, 2) <= F(1, 7))
668 self.assertFalse(DummyRational(1, 2) >= F(3, 4))
669 self.assertTrue(DummyRational(1, 2) >= F(1, 2))
670 self.assertTrue(DummyRational(1, 2) >= F(1, 7))
671
672 def testComparisonsDummyFloat(self):
673 x = DummyFloat(1./3.)
674 y = F(1, 3)
675 self.assertTrue(x != y)
676 self.assertTrue(x < y or x > y)
677 self.assertFalse(x == y)
678 self.assertFalse(x <= y and x >= y)
679 self.assertTrue(y != x)
680 self.assertTrue(y < x or y > x)
681 self.assertFalse(y == x)
682 self.assertFalse(y <= x and y >= x)
683
684 def testMixedLess(self):
685 self.assertTrue(2 < F(5, 2))
686 self.assertFalse(2 < F(4, 2))
687 self.assertTrue(F(5, 2) < 3)
688 self.assertFalse(F(4, 2) < 2)
689
690 self.assertTrue(F(1, 2) < 0.6)
691 self.assertFalse(F(1, 2) < 0.4)
692 self.assertTrue(0.4 < F(1, 2))
693 self.assertFalse(0.5 < F(1, 2))
694
695 self.assertFalse(float('inf') < F(1, 2))
696 self.assertTrue(float('-inf') < F(0, 10))
697 self.assertFalse(float('nan') < F(-3, 7))
698 self.assertTrue(F(1, 2) < float('inf'))
699 self.assertFalse(F(17, 12) < float('-inf'))
700 self.assertFalse(F(144, -89) < float('nan'))
701
702 def testMixedLessEqual(self):
703 self.assertTrue(0.5 <= F(1, 2))
704 self.assertFalse(0.6 <= F(1, 2))
705 self.assertTrue(F(1, 2) <= 0.5)
706 self.assertFalse(F(1, 2) <= 0.4)
707 self.assertTrue(2 <= F(4, 2))
708 self.assertFalse(2 <= F(3, 2))
709 self.assertTrue(F(4, 2) <= 2)
710 self.assertFalse(F(5, 2) <= 2)
711
712 self.assertFalse(float('inf') <= F(1, 2))
713 self.assertTrue(float('-inf') <= F(0, 10))
714 self.assertFalse(float('nan') <= F(-3, 7))
715 self.assertTrue(F(1, 2) <= float('inf'))
716 self.assertFalse(F(17, 12) <= float('-inf'))
717 self.assertFalse(F(144, -89) <= float('nan'))
718
719 def testBigFloatComparisons(self):
720 # Because 10**23 can't be represented exactly as a float:
721 self.assertFalse(F(10**23) == float(10**23))
722 # The first test demonstrates why these are important.
723 self.assertFalse(1e23 < float(F(math.trunc(1e23) + 1)))
724 self.assertTrue(1e23 < F(math.trunc(1e23) + 1))
725 self.assertFalse(1e23 <= F(math.trunc(1e23) - 1))
726 self.assertTrue(1e23 > F(math.trunc(1e23) - 1))
727 self.assertFalse(1e23 >= F(math.trunc(1e23) + 1))
728
729 def testBigComplexComparisons(self):
730 self.assertFalse(F(10**23) == complex(10**23))
731 self.assertRaises(TypeError, operator.gt, F(10**23), complex(10**23))
732 self.assertRaises(TypeError, operator.le, F(10**23), complex(10**23))
733
734 x = F(3, 8)
735 z = complex(0.375, 0.0)
736 w = complex(0.375, 0.2)
737 self.assertTrue(x == z)
738 self.assertFalse(x != z)
739 self.assertFalse(x == w)
740 self.assertTrue(x != w)
741 for op in operator.lt, operator.le, operator.gt, operator.ge:
742 self.assertRaises(TypeError, op, x, z)
743 self.assertRaises(TypeError, op, z, x)
744 self.assertRaises(TypeError, op, x, w)
745 self.assertRaises(TypeError, op, w, x)
746
747 def testMixedEqual(self):
748 self.assertTrue(0.5 == F(1, 2))
749 self.assertFalse(0.6 == F(1, 2))
750 self.assertTrue(F(1, 2) == 0.5)
751 self.assertFalse(F(1, 2) == 0.4)
752 self.assertTrue(2 == F(4, 2))
753 self.assertFalse(2 == F(3, 2))
754 self.assertTrue(F(4, 2) == 2)
755 self.assertFalse(F(5, 2) == 2)
756 self.assertFalse(F(5, 2) == float('nan'))
757 self.assertFalse(float('nan') == F(3, 7))
758 self.assertFalse(F(5, 2) == float('inf'))
759 self.assertFalse(float('-inf') == F(2, 5))
760
761 def testStringification(self):
762 self.assertEqual("Fraction(7, 3)", repr(F(7, 3)))
763 self.assertEqual("Fraction(6283185307, 2000000000)",
764 repr(F('3.1415926535')))
765 self.assertEqual("Fraction(-1, 100000000000000000000)",
766 repr(F(1, -10**20)))
767 self.assertEqual("7/3", str(F(7, 3)))
768 self.assertEqual("7", str(F(7, 1)))
769
770 def testHash(self):
771 hmod = sys.hash_info.modulus
772 hinf = sys.hash_info.inf
773 self.assertEqual(hash(2.5), hash(F(5, 2)))
774 self.assertEqual(hash(10**50), hash(F(10**50)))
775 self.assertNotEqual(hash(float(10**23)), hash(F(10**23)))
776 self.assertEqual(hinf, hash(F(1, hmod)))
777 # Check that __hash__ produces the same value as hash(), for
778 # consistency with int and Decimal. (See issue #10356.)
779 self.assertEqual(hash(F(-1)), F(-1).__hash__())
780
781 def testApproximatePi(self):
782 # Algorithm borrowed from
783 # http://docs.python.org/lib/decimal-recipes.html
784 three = F(3)
785 lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
786 while abs(s - lasts) > F(1, 10**9):
787 lasts = s
788 n, na = n+na, na+8
789 d, da = d+da, da+32
790 t = (t * n) / d
791 s += t
792 self.assertAlmostEqual(math.pi, s)
793
794 def testApproximateCos1(self):
795 # Algorithm borrowed from
796 # http://docs.python.org/lib/decimal-recipes.html
797 x = F(1)
798 i, lasts, s, fact, num, sign = 0, 0, F(1), 1, 1, 1
799 while abs(s - lasts) > F(1, 10**9):
800 lasts = s
801 i += 2
802 fact *= i * (i-1)
803 num *= x * x
804 sign *= -1
805 s += num / fact * sign
806 self.assertAlmostEqual(math.cos(1), s)
807
808 def test_copy_deepcopy_pickle(self):
809 r = F(13, 7)
810 dr = DummyFraction(13, 7)
811 for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
812 self.assertEqual(r, loads(dumps(r, proto)))
813 self.assertEqual(id(r), id(copy(r)))
814 self.assertEqual(id(r), id(deepcopy(r)))
815 self.assertNotEqual(id(dr), id(copy(dr)))
816 self.assertNotEqual(id(dr), id(deepcopy(dr)))
817 self.assertTypedEquals(dr, copy(dr))
818 self.assertTypedEquals(dr, deepcopy(dr))
819
820 def test_slots(self):
821 # Issue 4998
822 r = F(13, 7)
823 self.assertRaises(AttributeError, setattr, r, 'a', 10)
824
825 def test_int_subclass(self):
826 class ESC[4;38;5;81mmyint(ESC[4;38;5;149mint):
827 def __mul__(self, other):
828 return type(self)(int(self) * int(other))
829 def __floordiv__(self, other):
830 return type(self)(int(self) // int(other))
831 def __mod__(self, other):
832 x = type(self)(int(self) % int(other))
833 return x
834 @property
835 def numerator(self):
836 return type(self)(int(self))
837 @property
838 def denominator(self):
839 return type(self)(1)
840
841 f = fractions.Fraction(myint(1 * 3), myint(2 * 3))
842 self.assertEqual(f.numerator, 1)
843 self.assertEqual(f.denominator, 2)
844 self.assertEqual(type(f.numerator), myint)
845 self.assertEqual(type(f.denominator), myint)
846
847 def test_format_no_presentation_type(self):
848 # Triples (fraction, specification, expected_result)
849 testcases = [
850 (F(1, 3), '', '1/3'),
851 (F(-1, 3), '', '-1/3'),
852 (F(3), '', '3'),
853 (F(-3), '', '-3'),
854 ]
855 for fraction, spec, expected in testcases:
856 with self.subTest(fraction=fraction, spec=spec):
857 self.assertEqual(format(fraction, spec), expected)
858
859 def test_format_e_presentation_type(self):
860 # Triples (fraction, specification, expected_result)
861 testcases = [
862 (F(2, 3), '.6e', '6.666667e-01'),
863 (F(3, 2), '.6e', '1.500000e+00'),
864 (F(2, 13), '.6e', '1.538462e-01'),
865 (F(2, 23), '.6e', '8.695652e-02'),
866 (F(2, 33), '.6e', '6.060606e-02'),
867 (F(13, 2), '.6e', '6.500000e+00'),
868 (F(20, 2), '.6e', '1.000000e+01'),
869 (F(23, 2), '.6e', '1.150000e+01'),
870 (F(33, 2), '.6e', '1.650000e+01'),
871 (F(2, 3), '.6e', '6.666667e-01'),
872 (F(3, 2), '.6e', '1.500000e+00'),
873 # Zero
874 (F(0), '.3e', '0.000e+00'),
875 # Powers of 10, to exercise the log10 boundary logic
876 (F(1, 1000), '.3e', '1.000e-03'),
877 (F(1, 100), '.3e', '1.000e-02'),
878 (F(1, 10), '.3e', '1.000e-01'),
879 (F(1, 1), '.3e', '1.000e+00'),
880 (F(10), '.3e', '1.000e+01'),
881 (F(100), '.3e', '1.000e+02'),
882 (F(1000), '.3e', '1.000e+03'),
883 # Boundary where we round up to the next power of 10
884 (F('99.999994999999'), '.6e', '9.999999e+01'),
885 (F('99.999995'), '.6e', '1.000000e+02'),
886 (F('99.999995000001'), '.6e', '1.000000e+02'),
887 # Negatives
888 (F(-2, 3), '.6e', '-6.666667e-01'),
889 (F(-3, 2), '.6e', '-1.500000e+00'),
890 (F(-100), '.6e', '-1.000000e+02'),
891 # Large and small
892 (F('1e1000'), '.3e', '1.000e+1000'),
893 (F('1e-1000'), '.3e', '1.000e-1000'),
894 # Using 'E' instead of 'e' should give us a capital 'E'
895 (F(2, 3), '.6E', '6.666667E-01'),
896 # Tiny precision
897 (F(2, 3), '.1e', '6.7e-01'),
898 (F('0.995'), '.0e', '1e+00'),
899 # Default precision is 6
900 (F(22, 7), 'e', '3.142857e+00'),
901 # Alternate form forces a decimal point
902 (F('0.995'), '#.0e', '1.e+00'),
903 # Check that padding takes the exponent into account.
904 (F(22, 7), '11.6e', '3.142857e+00'),
905 (F(22, 7), '12.6e', '3.142857e+00'),
906 (F(22, 7), '13.6e', ' 3.142857e+00'),
907 # Thousands separators
908 (F('1234567.123456'), ',.5e', '1.23457e+06'),
909 (F('123.123456'), '012_.2e', '0_001.23e+02'),
910 # z flag is legal, but never makes a difference to the output
911 (F(-1, 7**100), 'z.6e', '-3.091690e-85'),
912 ]
913 for fraction, spec, expected in testcases:
914 with self.subTest(fraction=fraction, spec=spec):
915 self.assertEqual(format(fraction, spec), expected)
916
917 def test_format_f_presentation_type(self):
918 # Triples (fraction, specification, expected_result)
919 testcases = [
920 # Simple .f formatting
921 (F(0, 1), '.2f', '0.00'),
922 (F(1, 3), '.2f', '0.33'),
923 (F(2, 3), '.2f', '0.67'),
924 (F(4, 3), '.2f', '1.33'),
925 (F(1, 8), '.2f', '0.12'),
926 (F(3, 8), '.2f', '0.38'),
927 (F(1, 13), '.2f', '0.08'),
928 (F(1, 199), '.2f', '0.01'),
929 (F(1, 200), '.2f', '0.00'),
930 (F(22, 7), '.5f', '3.14286'),
931 (F('399024789'), '.2f', '399024789.00'),
932 # Large precision (more than float can provide)
933 (F(104348, 33215), '.50f',
934 '3.14159265392142104470871594159265392142104470871594'),
935 # Precision defaults to 6 if not given
936 (F(22, 7), 'f', '3.142857'),
937 (F(0), 'f', '0.000000'),
938 (F(-22, 7), 'f', '-3.142857'),
939 # Round-ties-to-even checks
940 (F('1.225'), '.2f', '1.22'),
941 (F('1.2250000001'), '.2f', '1.23'),
942 (F('1.2349999999'), '.2f', '1.23'),
943 (F('1.235'), '.2f', '1.24'),
944 (F('1.245'), '.2f', '1.24'),
945 (F('1.2450000001'), '.2f', '1.25'),
946 (F('1.2549999999'), '.2f', '1.25'),
947 (F('1.255'), '.2f', '1.26'),
948 (F('-1.225'), '.2f', '-1.22'),
949 (F('-1.2250000001'), '.2f', '-1.23'),
950 (F('-1.2349999999'), '.2f', '-1.23'),
951 (F('-1.235'), '.2f', '-1.24'),
952 (F('-1.245'), '.2f', '-1.24'),
953 (F('-1.2450000001'), '.2f', '-1.25'),
954 (F('-1.2549999999'), '.2f', '-1.25'),
955 (F('-1.255'), '.2f', '-1.26'),
956 # Negatives and sign handling
957 (F(2, 3), '.2f', '0.67'),
958 (F(2, 3), '-.2f', '0.67'),
959 (F(2, 3), '+.2f', '+0.67'),
960 (F(2, 3), ' .2f', ' 0.67'),
961 (F(-2, 3), '.2f', '-0.67'),
962 (F(-2, 3), '-.2f', '-0.67'),
963 (F(-2, 3), '+.2f', '-0.67'),
964 (F(-2, 3), ' .2f', '-0.67'),
965 # Formatting to zero places
966 (F(1, 2), '.0f', '0'),
967 (F(-1, 2), '.0f', '-0'),
968 (F(22, 7), '.0f', '3'),
969 (F(-22, 7), '.0f', '-3'),
970 # Formatting to zero places, alternate form
971 (F(1, 2), '#.0f', '0.'),
972 (F(-1, 2), '#.0f', '-0.'),
973 (F(22, 7), '#.0f', '3.'),
974 (F(-22, 7), '#.0f', '-3.'),
975 # z flag for suppressing negative zeros
976 (F('-0.001'), 'z.2f', '0.00'),
977 (F('-0.001'), '-z.2f', '0.00'),
978 (F('-0.001'), '+z.2f', '+0.00'),
979 (F('-0.001'), ' z.2f', ' 0.00'),
980 (F('0.001'), 'z.2f', '0.00'),
981 (F('0.001'), '-z.2f', '0.00'),
982 (F('0.001'), '+z.2f', '+0.00'),
983 (F('0.001'), ' z.2f', ' 0.00'),
984 # Specifying a minimum width
985 (F(2, 3), '6.2f', ' 0.67'),
986 (F(12345), '6.2f', '12345.00'),
987 (F(12345), '12f', '12345.000000'),
988 # Fill and alignment
989 (F(2, 3), '>6.2f', ' 0.67'),
990 (F(2, 3), '<6.2f', '0.67 '),
991 (F(2, 3), '^3.2f', '0.67'),
992 (F(2, 3), '^4.2f', '0.67'),
993 (F(2, 3), '^5.2f', '0.67 '),
994 (F(2, 3), '^6.2f', ' 0.67 '),
995 (F(2, 3), '^7.2f', ' 0.67 '),
996 (F(2, 3), '^8.2f', ' 0.67 '),
997 # '=' alignment
998 (F(-2, 3), '=+8.2f', '- 0.67'),
999 (F(2, 3), '=+8.2f', '+ 0.67'),
1000 # Fill character
1001 (F(-2, 3), 'X>3.2f', '-0.67'),
1002 (F(-2, 3), 'X>7.2f', 'XX-0.67'),
1003 (F(-2, 3), 'X<7.2f', '-0.67XX'),
1004 (F(-2, 3), 'X^7.2f', 'X-0.67X'),
1005 (F(-2, 3), 'X=7.2f', '-XX0.67'),
1006 (F(-2, 3), ' >7.2f', ' -0.67'),
1007 # Corner cases: weird fill characters
1008 (F(-2, 3), '\x00>7.2f', '\x00\x00-0.67'),
1009 (F(-2, 3), '\n>7.2f', '\n\n-0.67'),
1010 (F(-2, 3), '\t>7.2f', '\t\t-0.67'),
1011 (F(-2, 3), '>>7.2f', '>>-0.67'),
1012 (F(-2, 3), '<>7.2f', '<<-0.67'),
1013 (F(-2, 3), '→>7.2f', '→→-0.67'),
1014 # Zero-padding
1015 (F(-2, 3), '07.2f', '-000.67'),
1016 (F(-2, 3), '-07.2f', '-000.67'),
1017 (F(2, 3), '+07.2f', '+000.67'),
1018 (F(2, 3), ' 07.2f', ' 000.67'),
1019 # An isolated zero is a minimum width, not a zero-pad flag.
1020 # So unlike zero-padding, it's legal in combination with alignment.
1021 (F(2, 3), '0.2f', '0.67'),
1022 (F(2, 3), '>0.2f', '0.67'),
1023 (F(2, 3), '<0.2f', '0.67'),
1024 (F(2, 3), '^0.2f', '0.67'),
1025 (F(2, 3), '=0.2f', '0.67'),
1026 # Corner case: zero-padding _and_ a zero minimum width.
1027 (F(2, 3), '00.2f', '0.67'),
1028 # Thousands separator (only affects portion before the point)
1029 (F(2, 3), ',.2f', '0.67'),
1030 (F(2, 3), ',.7f', '0.6666667'),
1031 (F('123456.789'), ',.2f', '123,456.79'),
1032 (F('1234567'), ',.2f', '1,234,567.00'),
1033 (F('12345678'), ',.2f', '12,345,678.00'),
1034 (F('12345678'), ',f', '12,345,678.000000'),
1035 # Underscore as thousands separator
1036 (F(2, 3), '_.2f', '0.67'),
1037 (F(2, 3), '_.7f', '0.6666667'),
1038 (F('123456.789'), '_.2f', '123_456.79'),
1039 (F('1234567'), '_.2f', '1_234_567.00'),
1040 (F('12345678'), '_.2f', '12_345_678.00'),
1041 # Thousands and zero-padding
1042 (F('1234.5678'), '07,.2f', '1,234.57'),
1043 (F('1234.5678'), '08,.2f', '1,234.57'),
1044 (F('1234.5678'), '09,.2f', '01,234.57'),
1045 (F('1234.5678'), '010,.2f', '001,234.57'),
1046 (F('1234.5678'), '011,.2f', '0,001,234.57'),
1047 (F('1234.5678'), '012,.2f', '0,001,234.57'),
1048 (F('1234.5678'), '013,.2f', '00,001,234.57'),
1049 (F('1234.5678'), '014,.2f', '000,001,234.57'),
1050 (F('1234.5678'), '015,.2f', '0,000,001,234.57'),
1051 (F('1234.5678'), '016,.2f', '0,000,001,234.57'),
1052 (F('-1234.5678'), '07,.2f', '-1,234.57'),
1053 (F('-1234.5678'), '08,.2f', '-1,234.57'),
1054 (F('-1234.5678'), '09,.2f', '-1,234.57'),
1055 (F('-1234.5678'), '010,.2f', '-01,234.57'),
1056 (F('-1234.5678'), '011,.2f', '-001,234.57'),
1057 (F('-1234.5678'), '012,.2f', '-0,001,234.57'),
1058 (F('-1234.5678'), '013,.2f', '-0,001,234.57'),
1059 (F('-1234.5678'), '014,.2f', '-00,001,234.57'),
1060 (F('-1234.5678'), '015,.2f', '-000,001,234.57'),
1061 (F('-1234.5678'), '016,.2f', '-0,000,001,234.57'),
1062 # Corner case: no decimal point
1063 (F('-1234.5678'), '06,.0f', '-1,235'),
1064 (F('-1234.5678'), '07,.0f', '-01,235'),
1065 (F('-1234.5678'), '08,.0f', '-001,235'),
1066 (F('-1234.5678'), '09,.0f', '-0,001,235'),
1067 # Corner-case - zero-padding specified through fill and align
1068 # instead of the zero-pad character - in this case, treat '0' as a
1069 # regular fill character and don't attempt to insert commas into
1070 # the filled portion. This differs from the int and float
1071 # behaviour.
1072 (F('1234.5678'), '0=12,.2f', '00001,234.57'),
1073 # Corner case where it's not clear whether the '0' indicates zero
1074 # padding or gives the minimum width, but there's still an obvious
1075 # answer to give. We want this to work in case the minimum width
1076 # is being inserted programmatically: spec = f'{width}.2f'.
1077 (F('12.34'), '0.2f', '12.34'),
1078 (F('12.34'), 'X>0.2f', '12.34'),
1079 # 'F' should work identically to 'f'
1080 (F(22, 7), '.5F', '3.14286'),
1081 # %-specifier
1082 (F(22, 7), '.2%', '314.29%'),
1083 (F(1, 7), '.2%', '14.29%'),
1084 (F(1, 70), '.2%', '1.43%'),
1085 (F(1, 700), '.2%', '0.14%'),
1086 (F(1, 7000), '.2%', '0.01%'),
1087 (F(1, 70000), '.2%', '0.00%'),
1088 (F(1, 7), '.0%', '14%'),
1089 (F(1, 7), '#.0%', '14.%'),
1090 (F(100, 7), ',.2%', '1,428.57%'),
1091 (F(22, 7), '7.2%', '314.29%'),
1092 (F(22, 7), '8.2%', ' 314.29%'),
1093 (F(22, 7), '08.2%', '0314.29%'),
1094 # Test cases from #67790 and discuss.python.org Ideas thread.
1095 (F(1, 3), '.2f', '0.33'),
1096 (F(1, 8), '.2f', '0.12'),
1097 (F(3, 8), '.2f', '0.38'),
1098 (F(2545, 1000), '.2f', '2.54'),
1099 (F(2549, 1000), '.2f', '2.55'),
1100 (F(2635, 1000), '.2f', '2.64'),
1101 (F(1, 100), '.1f', '0.0'),
1102 (F(49, 1000), '.1f', '0.0'),
1103 (F(51, 1000), '.1f', '0.1'),
1104 (F(149, 1000), '.1f', '0.1'),
1105 (F(151, 1000), '.1f', '0.2'),
1106 ]
1107 for fraction, spec, expected in testcases:
1108 with self.subTest(fraction=fraction, spec=spec):
1109 self.assertEqual(format(fraction, spec), expected)
1110
1111 def test_format_g_presentation_type(self):
1112 # Triples (fraction, specification, expected_result)
1113 testcases = [
1114 (F('0.000012345678'), '.6g', '1.23457e-05'),
1115 (F('0.00012345678'), '.6g', '0.000123457'),
1116 (F('0.0012345678'), '.6g', '0.00123457'),
1117 (F('0.012345678'), '.6g', '0.0123457'),
1118 (F('0.12345678'), '.6g', '0.123457'),
1119 (F('1.2345678'), '.6g', '1.23457'),
1120 (F('12.345678'), '.6g', '12.3457'),
1121 (F('123.45678'), '.6g', '123.457'),
1122 (F('1234.5678'), '.6g', '1234.57'),
1123 (F('12345.678'), '.6g', '12345.7'),
1124 (F('123456.78'), '.6g', '123457'),
1125 (F('1234567.8'), '.6g', '1.23457e+06'),
1126 # Rounding up cases
1127 (F('9.99999e+2'), '.4g', '1000'),
1128 (F('9.99999e-8'), '.4g', '1e-07'),
1129 (F('9.99999e+8'), '.4g', '1e+09'),
1130 # Check round-ties-to-even behaviour
1131 (F('-0.115'), '.2g', '-0.12'),
1132 (F('-0.125'), '.2g', '-0.12'),
1133 (F('-0.135'), '.2g', '-0.14'),
1134 (F('-0.145'), '.2g', '-0.14'),
1135 (F('0.115'), '.2g', '0.12'),
1136 (F('0.125'), '.2g', '0.12'),
1137 (F('0.135'), '.2g', '0.14'),
1138 (F('0.145'), '.2g', '0.14'),
1139 # Trailing zeros and decimal point suppressed by default ...
1140 (F(0), '.6g', '0'),
1141 (F('123.400'), '.6g', '123.4'),
1142 (F('123.000'), '.6g', '123'),
1143 (F('120.000'), '.6g', '120'),
1144 (F('12000000'), '.6g', '1.2e+07'),
1145 # ... but not when alternate form is in effect
1146 (F(0), '#.6g', '0.00000'),
1147 (F('123.400'), '#.6g', '123.400'),
1148 (F('123.000'), '#.6g', '123.000'),
1149 (F('120.000'), '#.6g', '120.000'),
1150 (F('12000000'), '#.6g', '1.20000e+07'),
1151 # 'G' format (uses 'E' instead of 'e' for the exponent indicator)
1152 (F('123.45678'), '.6G', '123.457'),
1153 (F('1234567.8'), '.6G', '1.23457E+06'),
1154 # Default precision is 6 significant figures
1155 (F('3.1415926535'), 'g', '3.14159'),
1156 # Precision 0 is treated the same as precision 1.
1157 (F('0.000031415'), '.0g', '3e-05'),
1158 (F('0.00031415'), '.0g', '0.0003'),
1159 (F('0.31415'), '.0g', '0.3'),
1160 (F('3.1415'), '.0g', '3'),
1161 (F('3.1415'), '#.0g', '3.'),
1162 (F('31.415'), '.0g', '3e+01'),
1163 (F('31.415'), '#.0g', '3.e+01'),
1164 (F('0.000031415'), '.1g', '3e-05'),
1165 (F('0.00031415'), '.1g', '0.0003'),
1166 (F('0.31415'), '.1g', '0.3'),
1167 (F('3.1415'), '.1g', '3'),
1168 (F('3.1415'), '#.1g', '3.'),
1169 (F('31.415'), '.1g', '3e+01'),
1170 # Thousands separator
1171 (F(2**64), '_.25g', '18_446_744_073_709_551_616'),
1172 # As with 'e' format, z flag is legal, but has no effect
1173 (F(-1, 7**100), 'zg', '-3.09169e-85'),
1174 ]
1175 for fraction, spec, expected in testcases:
1176 with self.subTest(fraction=fraction, spec=spec):
1177 self.assertEqual(format(fraction, spec), expected)
1178
1179 def test_invalid_formats(self):
1180 fraction = F(2, 3)
1181 with self.assertRaises(TypeError):
1182 format(fraction, None)
1183
1184 invalid_specs = [
1185 'Q6f', # regression test
1186 # illegal to use fill or alignment when zero padding
1187 'X>010f',
1188 'X<010f',
1189 'X^010f',
1190 'X=010f',
1191 '0>010f',
1192 '0<010f',
1193 '0^010f',
1194 '0=010f',
1195 '>010f',
1196 '<010f',
1197 '^010f',
1198 '=010e',
1199 '=010f',
1200 '=010g',
1201 '=010%',
1202 '>00.2f',
1203 '>00f',
1204 # Too many zeros - minimum width should not have leading zeros
1205 '006f',
1206 # Leading zeros in precision
1207 '.010f',
1208 '.02f',
1209 '.000f',
1210 # Missing precision
1211 '.e',
1212 '.f',
1213 '.g',
1214 '.%',
1215 # Z instead of z for negative zero suppression
1216 'Z.2f'
1217 ]
1218 for spec in invalid_specs:
1219 with self.subTest(spec=spec):
1220 with self.assertRaises(ValueError):
1221 format(fraction, spec)
1222
1223
1224 if __name__ == '__main__':
1225 unittest.main()