Files
RustPython/Lib/test/test_complex.py
T
Jeong, YunWon f9b177719b Fix formatting, numeric, unicode, codec, complex and marshal mismatches found by differential testing (#8600)
* Fix %-formatting of bytes precision, width and %c errors

`format_bytes` subtracted the byte length from the field width without
saturating, so `b'%1s' % (b'abcde',)` aborted with a capacity overflow.
A precision written as a bare dot now truncates to nothing, and `%r`/`%a`
on bytes now honour the precision and width like the other conversions.

`%c` with a bytes, bytearray or str argument that is not one unit long
now names the argument by its length instead of by its type.

Assisted-by: Claude Code:claude-opus-5

* Fix format spec handling of grouping, bool, 'c' and complex

A grouping option next to an unrecognised presentation type now reports
"Cannot specify ',' with 'a'." instead of falling through to the type
check. `format(True, spec)` now validates the spec the way an int does.

The 'c' type now pads and aligns its character, and an integer outside
the C long range raises OverflowError rather than reporting a code point
out of range.

A complex formatted with the 'n'/'g' types or with a precision and no
type now goes through the general format without forcing a fraction.

Assisted-by: Claude Code:claude-opus-5

* Round floats at a negative ndigits from the exact decimal digits

Dividing by a power of ten rounded twice: once when the quotient was
stored and again at the tie, so e.g. `round(2.5e2, -2)` came out as 300.0.
The digits now come from the exact decimal expansion of the value.

Assisted-by: Claude Code:claude-opus-5

* Report the requested base in int literal errors and reject a bare sign

An invalid literal parsed with base 0 named the base that the prefix
turned out to mean rather than 0. A string of nothing but a sign was
taken for the old octal form and returned 0 instead of raising.

Assisted-by: Claude Code:claude-opus-5

* Split, strip and expand tabs over the Py_UNICODE_ISSPACE set

`str.split`, `rsplit`, `strip`, `lstrip` and `rstrip` with no separator
used Rust's whitespace predicate, which differs from the 29 code points
`Py_UNICODE_ISSPACE` names: U+001C-U+001F and U+0085 were skipped and
U+200B was treated as a separator.

`expandtabs` went through `str`, so it dropped the lone surrogates of a
WTF-8 string; it now works on `Wtf8` throughout.

Indexing a str out of range now says "string index out of range".

Assisted-by: Claude Code:claude-opus-5

* Read Unicode numeric values as exact rationals

`DerivedNumericValues.txt` field 1 carries a rounded decimal, so
`unicodedata.numeric('⅐')` and its neighbours came back short of the
value CPython reports. The generator now reads the rational in field 3,
and takes the 3.2 values from field 8 of `UnicodeData-3.2.0.txt`.

Assisted-by: Claude Code:claude-opus-5

* Return a mappingproxy from Pattern.groupindex

`pattern_groupindex` wraps the group index in a dict proxy, and hands
back a plain dict only when the pattern has no named group.

Assisted-by: Claude Code:claude-opus-5

* Fix the utf-16/32/7 codecs' error handling

The utf-32 decoder dropped a code point above U+10FFFF instead of calling
the error handler, and both the utf-16 and utf-32 handlers were told the
encoding was "utf-16"/"utf-32" whichever byte order the data was in.

The encoders now take a bytes replacement from the handler as it stands,
rejecting one that does not fill whole code units, rather than iterating
over it as text; a str replacement from the utf-16 encoder now splits an
astral code point into a surrogate pair.

The utf-7 decoder names its encoding "utf7", as its codec does.

Assisted-by: Claude Code:claude-opus-5

* Rework complex multiplication, division and power

Division now divides by whichever part of the divisor is larger, the way
`_Py_c_quot` does, and both it and multiplication recover the infinities
that the plain formulas turn into nan, following C11 Annex G. An operand
that is a real number is now multiplied and divided component-wise, which
keeps the sign of a zero and the other part of an infinity; a real
numerator has its own quotient so that its zero keeps a sign too.

An integer exponent no greater than 100 in magnitude is now reached by
repeated multiplication rather than through the polar form, so e.g.
`(1+2j) ** 2` is exact. A zero exponent gives 1, and an exponent with no
imaginary part no longer reaches for a logarithm that turns an infinite
magnitude into a nan. A result that came out infinite raises
OverflowError.

`complex() arg is a malformed string` is replaced by `could not convert
string to complex: ...` when the string carries a misplaced underscore,
`complex division by zero` by `division by zero`, and the message for
zero raised to a negative or complex power no longer names the base.

Assisted-by: Claude Code:claude-opus-5

* Intern the string constants that read as names

A code object's string constants were interned by length, so a short
string that is not a name was interned and a long name was not. They are
now picked out the way `all_name_chars` does. The one-character latin-1
strings are interned as well, so that every route to one of them lands on
the same object.

Assisted-by: Claude Code:claude-opus-5

* Honour the marshal version and separate its EOF errors

Versions below 2 now write a float or complex as its digits under
TYPE_FLOAT/TYPE_COMPLEX, versions from 4 on write a tuple of fewer than
256 items under TYPE_SMALL_TUPLE and a long ascii string under
TYPE_ASCII, and a string is marked interned only when it is.

`marshal.loads` now tells apart the three ways its data can run out:
"EOF read where object expected" where an object was to start, "EOF read
where not expected" where a single byte was, and "marshal data too short"
where a run of bytes was cut short.

Assisted-by: Claude Code:claude-opus-5
2026-08-29 22:43:11 +09:00

1028 lines
45 KiB
Python
Vendored

import unittest
import sys
from test import support
from test.support.testcase import ComplexesAreIdenticalMixin
from test.support.numbers import (
VALID_UNDERSCORE_LITERALS,
INVALID_UNDERSCORE_LITERALS,
)
from random import random
from math import isnan, copysign
import operator
INF = float("inf")
NAN = float("nan")
DBL_MAX = sys.float_info.max
# These tests ensure that complex math does the right thing
ZERO_DIVISION = (
(1+1j, 0+0j),
(1+1j, 0.0),
(1+1j, 0),
(1.0, 0+0j),
(1, 0+0j),
)
class WithIndex:
def __init__(self, value):
self.value = value
def __index__(self):
return self.value
class WithFloat:
def __init__(self, value):
self.value = value
def __float__(self):
return self.value
class ComplexSubclass(complex):
pass
class OtherComplexSubclass(complex):
pass
class MyInt:
def __init__(self, value):
self.value = value
def __int__(self):
return self.value
class WithComplex:
def __init__(self, value):
self.value = value
def __complex__(self):
return self.value
class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
def assertAlmostEqual(self, a, b):
if isinstance(a, complex):
if isinstance(b, complex):
unittest.TestCase.assertAlmostEqual(self, a.real, b.real)
unittest.TestCase.assertAlmostEqual(self, a.imag, b.imag)
else:
unittest.TestCase.assertAlmostEqual(self, a.real, b)
unittest.TestCase.assertAlmostEqual(self, a.imag, 0.)
else:
if isinstance(b, complex):
unittest.TestCase.assertAlmostEqual(self, a, b.real)
unittest.TestCase.assertAlmostEqual(self, 0., b.imag)
else:
unittest.TestCase.assertAlmostEqual(self, a, b)
def assertClose(self, x, y, eps=1e-9):
"""Return true iff complexes x and y "are close"."""
# put the one with larger magnitude second
if abs(x) > abs(y):
x, y = y, x
if y == 0:
return abs(x) < eps
if x == 0:
return abs(y) < eps
# check that relative difference < eps
self.assertTrue(abs(x-y)/abs(y) < eps)
def check_div(self, x, y):
"""Compute complex z=x*y, and check that z/x==y and z/y==x."""
z = x * y
if x:
self.assertClose(z / x, y)
if y:
self.assertClose(z / y, x)
def test_truediv(self):
simple_real = [float(i) for i in range(-5, 6)]
simple_complex = [complex(x, y) for x in simple_real for y in simple_real]
for x in simple_complex:
for y in simple_complex:
self.check_div(x, y)
# A naive complex division algorithm (such as in 2.0) is very prone to
# nonsense errors for these (overflows and underflows).
self.check_div(complex(1e200, 1e200), 1+0j)
self.check_div(complex(1e-200, 1e-200), 1+0j)
# Smith's algorithm has several sources of inaccuracy
# for components of the result. In examples below,
# it's cancellation of digits in computation of sum.
self.check_div(1e-09+1j, 1+1j)
self.check_div(8.289760544677449e-09+0.13257307440728516j,
0.9059966714925808+0.5054864708672686j)
# Just for fun.
for i in range(100):
x = complex(random(), random())
y = complex(random(), random())
self.check_div(x, y)
y = complex(1e10*y.real, y.imag)
self.check_div(x, y)
self.assertAlmostEqual(complex.__truediv__(2+0j, 1+1j), 1-1j)
self.assertRaises(TypeError, operator.truediv, 1j, None)
self.assertRaises(TypeError, operator.truediv, None, 1j)
for denom_real, denom_imag in [(0, NAN), (NAN, 0), (NAN, NAN)]:
z = complex(0, 0) / complex(denom_real, denom_imag)
self.assertTrue(isnan(z.real))
self.assertTrue(isnan(z.imag))
z = float(0) / complex(denom_real, denom_imag)
self.assertTrue(isnan(z.real))
self.assertTrue(isnan(z.imag))
self.assertComplexesAreIdentical(complex(INF, NAN) / 2,
complex(INF, NAN))
self.assertComplexesAreIdentical(complex(INF, 1)/(0.0+1j),
complex(NAN, -INF))
# test recover of infs if numerator has infs and denominator is finite
self.assertComplexesAreIdentical(complex(INF, -INF)/(1+0j),
complex(INF, -INF))
self.assertComplexesAreIdentical(complex(INF, INF)/(0.0+1j),
complex(INF, -INF))
self.assertComplexesAreIdentical(complex(NAN, INF)/complex(2**1000, 2**-1000),
complex(INF, INF))
self.assertComplexesAreIdentical(complex(INF, NAN)/complex(2**1000, 2**-1000),
complex(INF, -INF))
# test recover of zeros if denominator is infinite
self.assertComplexesAreIdentical((1+1j)/complex(INF, INF), (0.0+0j))
self.assertComplexesAreIdentical((1+1j)/complex(INF, -INF), (0.0+0j))
self.assertComplexesAreIdentical((1+1j)/complex(-INF, INF),
complex(0.0, -0.0))
self.assertComplexesAreIdentical((1+1j)/complex(-INF, -INF),
complex(-0.0, 0))
self.assertComplexesAreIdentical((INF+1j)/complex(INF, INF),
complex(NAN, NAN))
self.assertComplexesAreIdentical(complex(1, INF)/complex(INF, INF),
complex(NAN, NAN))
self.assertComplexesAreIdentical(complex(INF, 1)/complex(1, INF),
complex(NAN, NAN))
# mixed types
self.assertEqual((1+1j)/float(2), 0.5+0.5j)
self.assertEqual(float(1)/(1+2j), 0.2-0.4j)
self.assertEqual(float(1)/(-1+2j), -0.2-0.4j)
self.assertEqual(float(1)/(1-2j), 0.2+0.4j)
self.assertEqual(float(1)/(2+1j), 0.4-0.2j)
self.assertEqual(float(1)/(-2+1j), -0.4-0.2j)
self.assertEqual(float(1)/(2-1j), 0.4+0.2j)
self.assertComplexesAreIdentical(INF/(1+0j),
complex(INF, NAN))
self.assertComplexesAreIdentical(INF/(0.0+1j),
complex(NAN, -INF))
self.assertComplexesAreIdentical(INF/complex(2**1000, 2**-1000),
complex(INF, NAN))
self.assertComplexesAreIdentical(INF/complex(NAN, NAN),
complex(NAN, NAN))
self.assertComplexesAreIdentical(float(1)/complex(INF, INF), (0.0-0j))
self.assertComplexesAreIdentical(float(1)/complex(INF, -INF), (0.0+0j))
self.assertComplexesAreIdentical(float(1)/complex(-INF, INF),
complex(-0.0, -0.0))
self.assertComplexesAreIdentical(float(1)/complex(-INF, -INF),
complex(-0.0, 0))
self.assertComplexesAreIdentical(float(1)/complex(INF, NAN),
complex(0.0, -0.0))
self.assertComplexesAreIdentical(float(1)/complex(-INF, NAN),
complex(-0.0, -0.0))
self.assertComplexesAreIdentical(float(1)/complex(NAN, INF),
complex(0.0, -0.0))
self.assertComplexesAreIdentical(float(INF)/complex(NAN, INF),
complex(NAN, NAN))
def test_truediv_zero_division(self):
for a, b in ZERO_DIVISION:
with self.assertRaises(ZeroDivisionError):
a / b
def test_floordiv(self):
with self.assertRaises(TypeError):
(1+1j) // (1+0j)
with self.assertRaises(TypeError):
(1+1j) // 1.0
with self.assertRaises(TypeError):
(1+1j) // 1
with self.assertRaises(TypeError):
1.0 // (1+0j)
with self.assertRaises(TypeError):
1 // (1+0j)
def test_floordiv_zero_division(self):
for a, b in ZERO_DIVISION:
with self.assertRaises(TypeError):
a // b
def test_richcompare(self):
self.assertIs(complex.__eq__(1+1j, 1<<10000), False)
self.assertIs(complex.__lt__(1+1j, None), NotImplemented)
self.assertIs(complex.__eq__(1+1j, None), NotImplemented)
self.assertIs(complex.__eq__(1+1j, 1+1j), True)
self.assertIs(complex.__eq__(1+1j, 2+2j), False)
self.assertIs(complex.__ne__(1+1j, 1+1j), False)
self.assertIs(complex.__ne__(1+1j, 2+2j), True)
for i in range(1, 100):
f = i / 100.0
self.assertIs(complex.__eq__(f+0j, f), True)
self.assertIs(complex.__ne__(f+0j, f), False)
self.assertIs(complex.__eq__(complex(f, f), f), False)
self.assertIs(complex.__ne__(complex(f, f), f), True)
self.assertIs(complex.__lt__(1+1j, 2+2j), NotImplemented)
self.assertIs(complex.__le__(1+1j, 2+2j), NotImplemented)
self.assertIs(complex.__gt__(1+1j, 2+2j), NotImplemented)
self.assertIs(complex.__ge__(1+1j, 2+2j), NotImplemented)
self.assertRaises(TypeError, operator.lt, 1+1j, 2+2j)
self.assertRaises(TypeError, operator.le, 1+1j, 2+2j)
self.assertRaises(TypeError, operator.gt, 1+1j, 2+2j)
self.assertRaises(TypeError, operator.ge, 1+1j, 2+2j)
self.assertIs(operator.eq(1+1j, 1+1j), True)
self.assertIs(operator.eq(1+1j, 2+2j), False)
self.assertIs(operator.ne(1+1j, 1+1j), False)
self.assertIs(operator.ne(1+1j, 2+2j), True)
self.assertIs(operator.eq(1+1j, 2.0), False)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: True is not False
def test_richcompare_boundaries(self):
def check(n, deltas, is_equal, imag = 0.0):
for delta in deltas:
i = n + delta
z = complex(i, imag)
self.assertIs(complex.__eq__(z, i), is_equal(delta))
self.assertIs(complex.__ne__(z, i), not is_equal(delta))
# For IEEE-754 doubles the following should hold:
# x in [2 ** (52 + i), 2 ** (53 + i + 1)] -> x mod 2 ** i == 0
# where the interval is representable, of course.
for i in range(1, 10):
pow = 52 + i
mult = 2 ** i
check(2 ** pow, range(1, 101), lambda delta: delta % mult == 0)
check(2 ** pow, range(1, 101), lambda delta: False, float(i))
check(2 ** 53, range(-100, 0), lambda delta: True)
def test_add(self):
self.assertEqual(1j + int(+1), complex(+1, 1))
self.assertEqual(1j + int(-1), complex(-1, 1))
self.assertComplexesAreIdentical(complex(-0.0, -0.0) + (-0.0),
complex(-0.0, -0.0))
self.assertComplexesAreIdentical((-0.0) + complex(-0.0, -0.0),
complex(-0.0, -0.0))
self.assertRaises(OverflowError, operator.add, 1j, 10**1000)
self.assertRaises(TypeError, operator.add, 1j, None)
self.assertRaises(TypeError, operator.add, None, 1j)
def test_sub(self):
self.assertEqual(1j - int(+1), complex(-1, 1))
self.assertEqual(1j - int(-1), complex(1, 1))
self.assertComplexesAreIdentical(complex(-0.0, -0.0) - 0.0,
complex(-0.0, -0.0))
self.assertComplexesAreIdentical(-0.0 - complex(0.0, 0.0),
complex(-0.0, -0.0))
self.assertComplexesAreIdentical(complex(1, 2) - complex(2, 1),
complex(-1, 1))
self.assertComplexesAreIdentical(complex(2, 1) - complex(1, 2),
complex(1, -1))
self.assertRaises(OverflowError, operator.sub, 1j, 10**1000)
self.assertRaises(TypeError, operator.sub, 1j, None)
self.assertRaises(TypeError, operator.sub, None, 1j)
def test_mul(self):
self.assertEqual(1j * int(20), complex(0, 20))
self.assertEqual(1j * int(-1), complex(0, -1))
for c, r in [(2, complex(INF, 2)), (INF, complex(INF, INF)),
(0, complex(NAN, 0)), (-0.0, complex(NAN, -0.0)),
(NAN, complex(NAN, NAN))]:
with self.subTest(c=c, r=r):
self.assertComplexesAreIdentical(complex(INF, 1) * c, r)
self.assertComplexesAreIdentical(c * complex(INF, 1), r)
self.assertRaises(OverflowError, operator.mul, 1j, 10**1000)
self.assertRaises(TypeError, operator.mul, 1j, None)
self.assertRaises(TypeError, operator.mul, None, 1j)
for z, w, r in [(1e300+1j, complex(INF, INF), complex(NAN, INF)),
(1e300+1j, complex(NAN, INF), complex(-INF, INF)),
(1e300+1j, complex(INF, NAN), complex(INF, INF)),
(complex(INF, 1), complex(NAN, INF), complex(NAN, INF)),
(complex(INF, 1), complex(INF, NAN), complex(INF, NAN)),
(complex(NAN, 1), complex(1, INF), complex(-INF, NAN)),
(complex(1, NAN), complex(1, INF), complex(NAN, INF)),
(complex(1e200, NAN), complex(1e200, NAN), complex(INF, NAN)),
(complex(1e200, NAN), complex(NAN, 1e200), complex(NAN, INF)),
(complex(NAN, 1e200), complex(1e200, NAN), complex(NAN, INF)),
(complex(NAN, 1e200), complex(NAN, 1e200), complex(-INF, NAN)),
(complex(NAN, NAN), complex(NAN, NAN), complex(NAN, NAN))]:
with self.subTest(z=z, w=w, r=r):
self.assertComplexesAreIdentical(z * w, r)
self.assertComplexesAreIdentical(w * z, r)
def test_mod(self):
# % is no longer supported on complex numbers
with self.assertRaises(TypeError):
(1+1j) % (1+0j)
with self.assertRaises(TypeError):
(1+1j) % 1.0
with self.assertRaises(TypeError):
(1+1j) % 1
with self.assertRaises(TypeError):
1.0 % (1+0j)
with self.assertRaises(TypeError):
1 % (1+0j)
def test_mod_zero_division(self):
for a, b in ZERO_DIVISION:
with self.assertRaises(TypeError):
a % b
def test_divmod(self):
self.assertRaises(TypeError, divmod, 1+1j, 1+0j)
self.assertRaises(TypeError, divmod, 1+1j, 1.0)
self.assertRaises(TypeError, divmod, 1+1j, 1)
self.assertRaises(TypeError, divmod, 1.0, 1+0j)
self.assertRaises(TypeError, divmod, 1, 1+0j)
def test_divmod_zero_division(self):
for a, b in ZERO_DIVISION:
self.assertRaises(TypeError, divmod, a, b)
def test_pow(self):
self.assertAlmostEqual(pow(1+1j, 0+0j), 1.0)
self.assertAlmostEqual(pow(0+0j, 2+0j), 0.0)
self.assertEqual(pow(0+0j, 2000+0j), 0.0)
self.assertEqual(pow(0, 0+0j), 1.0)
self.assertEqual(pow(-1, 0+0j), 1.0)
self.assertRaises(ZeroDivisionError, pow, 0+0j, 1j)
self.assertRaises(ZeroDivisionError, pow, 0+0j, -1000)
self.assertAlmostEqual(pow(1j, -1), 1/1j)
self.assertAlmostEqual(pow(1j, 200), 1)
self.assertRaises(ValueError, pow, 1+1j, 1+1j, 1+1j)
self.assertRaises(OverflowError, pow, 1e200+1j, 1e200+1j)
self.assertRaises(OverflowError, pow, 1e200+1j, 5)
self.assertRaises(TypeError, pow, 1j, None)
self.assertRaises(TypeError, pow, None, 1j)
self.assertAlmostEqual(pow(1j, 0.5), 0.7071067811865476+0.7071067811865475j)
a = 3.33+4.43j
self.assertEqual(a ** 0j, 1)
self.assertEqual(a ** 0.+0.j, 1)
self.assertEqual(3j ** 0j, 1)
self.assertEqual(3j ** 0, 1)
try:
0j ** a
except ZeroDivisionError:
pass
else:
self.fail("should fail 0.0 to negative or complex power")
try:
0j ** (3-2j)
except ZeroDivisionError:
pass
else:
self.fail("should fail 0.0 to negative or complex power")
# The following is used to exercise certain code paths
self.assertEqual(a ** 105, a ** 105)
self.assertEqual(a ** -105, a ** -105)
self.assertEqual(a ** -30, a ** -30)
self.assertEqual(0.0j ** 0, 1)
b = 5.1+2.3j
self.assertRaises(ValueError, pow, a, b, 0)
# Check some boundary conditions; some of these used to invoke
# undefined behaviour (https://bugs.python.org/issue44698). We're
# not actually checking the results of these operations, just making
# sure they don't crash (for example when using clang's
# UndefinedBehaviourSanitizer).
values = (sys.maxsize, sys.maxsize+1, sys.maxsize-1,
-sys.maxsize, -sys.maxsize+1, -sys.maxsize+1)
for real in values:
for imag in values:
with self.subTest(real=real, imag=imag):
c = complex(real, imag)
try:
c ** real
except OverflowError:
pass
try:
c ** c
except OverflowError:
pass
# gh-113841: possible undefined division by 0 in _Py_c_pow()
x, y = 9j, 33j**3
with self.assertRaises(OverflowError):
x**y
def test_pow_with_small_integer_exponents(self):
# Check that small integer exponents are handled identically
# regardless of their type.
values = [
complex(5.0, 12.0),
complex(5.0e100, 12.0e100),
complex(-4.0, INF),
complex(INF, 0.0),
]
exponents = [-19, -5, -3, -2, -1, 0, 1, 2, 3, 5, 19]
for value in values:
for exponent in exponents:
with self.subTest(value=value, exponent=exponent):
try:
int_pow = value**exponent
except OverflowError:
int_pow = "overflow"
try:
float_pow = value**float(exponent)
except OverflowError:
float_pow = "overflow"
try:
complex_pow = value**complex(exponent)
except OverflowError:
complex_pow = "overflow"
self.assertEqual(str(float_pow), str(int_pow))
self.assertEqual(str(complex_pow), str(int_pow))
def test_boolcontext(self):
for i in range(100):
self.assertTrue(complex(random() + 1e-6, random() + 1e-6))
self.assertTrue(not complex(0.0, 0.0))
self.assertTrue(1j)
def test_conjugate(self):
self.assertEqual(complex(5.3, 9.8).conjugate(), 5.3-9.8j)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: DeprecationWarning not triggered
def test_constructor(self):
def check(z, x, y):
self.assertIs(type(z), complex)
self.assertFloatsAreIdentical(z.real, x)
self.assertFloatsAreIdentical(z.imag, y)
check(complex(), 0.0, 0.0)
check(complex(10), 10.0, 0.0)
check(complex(4.25), 4.25, 0.0)
check(complex(4.25+0j), 4.25, 0.0)
check(complex(4.25+0.5j), 4.25, 0.5)
check(complex(ComplexSubclass(4.25+0.5j)), 4.25, 0.5)
check(complex(WithComplex(4.25+0.5j)), 4.25, 0.5)
check(complex(1, 10), 1.0, 10.0)
check(complex(1, 10.0), 1.0, 10.0)
check(complex(1, 4.25), 1.0, 4.25)
check(complex(1.0, 10), 1.0, 10.0)
check(complex(4.25, 10), 4.25, 10.0)
check(complex(1.0, 10.0), 1.0, 10.0)
check(complex(4.25, 0.5), 4.25, 0.5)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'real' must be a real number, not complex"):
check(complex(4.25+0j, 0), 4.25, 0.0)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'real' must be a real number, not .*ComplexSubclass"):
check(complex(ComplexSubclass(4.25+0j), 0), 4.25, 0.0)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'real' must be a real number, not .*WithComplex"):
check(complex(WithComplex(4.25+0j), 0), 4.25, 0.0)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'real' must be a real number, not complex"):
check(complex(4.25j, 0), 0.0, 4.25)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'real' must be a real number, not complex"):
check(complex(0j, 4.25), 0.0, 4.25)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'imag' must be a real number, not complex"):
check(complex(0, 4.25+0j), 0.0, 4.25)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'imag' must be a real number, not .*ComplexSubclass"):
check(complex(0, ComplexSubclass(4.25+0j)), 0.0, 4.25)
with self.assertRaisesRegex(TypeError,
"argument 'imag' must be a real number, not .*WithComplex"):
complex(0, WithComplex(4.25+0j))
with self.assertWarnsRegex(DeprecationWarning,
"argument 'imag' must be a real number, not complex"):
check(complex(0.0, 4.25j), -4.25, 0.0)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'real' must be a real number, not complex"):
check(complex(4.25+0j, 0j), 4.25, 0.0)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'real' must be a real number, not complex"):
check(complex(4.25j, 0j), 0.0, 4.25)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'real' must be a real number, not complex"):
check(complex(0j, 4.25+0j), 0.0, 4.25)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'real' must be a real number, not complex"):
check(complex(0j, 4.25j), -4.25, 0.0)
check(complex(real=4.25), 4.25, 0.0)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'real' must be a real number, not complex"):
check(complex(real=4.25+0j), 4.25, 0.0)
with self.assertWarnsRegex(DeprecationWarning,
"argument 'real' must be a real number, not complex"):
check(complex(real=4.25+1.5j), 4.25, 1.5)
check(complex(imag=1.5), 0.0, 1.5)
check(complex(real=4.25, imag=1.5), 4.25, 1.5)
check(complex(4.25, imag=1.5), 4.25, 1.5)
# check that the sign of a zero in the real or imaginary part
# is preserved when constructing from two floats.
for x in 1.0, -1.0:
for y in 0.0, -0.0:
check(complex(x, y), x, y)
check(complex(y, x), y, x)
c = complex(4.25, 1.5)
self.assertIs(complex(c), c)
c2 = ComplexSubclass(c)
self.assertEqual(c2, c)
self.assertIs(type(c2), ComplexSubclass)
del c, c2
self.assertRaisesRegex(TypeError,
"argument must be a string or a number, not dict",
complex, {})
self.assertRaisesRegex(TypeError,
"argument must be a string or a number, not NoneType",
complex, None)
self.assertRaisesRegex(TypeError,
"argument 'real' must be a real number, not dict",
complex, {1:2}, 0)
self.assertRaisesRegex(TypeError,
"argument 'real' must be a real number, not str",
complex, '1', 0)
self.assertRaisesRegex(TypeError,
"argument 'imag' must be a real number, not dict",
complex, 0, {1:2})
self.assertRaisesRegex(TypeError,
"argument 'imag' must be a real number, not str",
complex, 0, '1')
self.assertRaises(TypeError, complex, WithComplex(1.5))
self.assertRaises(TypeError, complex, WithComplex(1))
self.assertRaises(TypeError, complex, WithComplex(None))
self.assertRaises(TypeError, complex, WithComplex(4.25+0j), object())
self.assertRaises(TypeError, complex, WithComplex(1.5), object())
self.assertRaises(TypeError, complex, WithComplex(1), object())
self.assertRaises(TypeError, complex, WithComplex(None), object())
class EvilExc(Exception):
pass
class evilcomplex:
def __complex__(self):
raise EvilExc
self.assertRaises(EvilExc, complex, evilcomplex())
check(complex(WithFloat(4.25)), 4.25, 0.0)
check(complex(WithFloat(4.25), 1.5), 4.25, 1.5)
check(complex(1.5, WithFloat(4.25)), 1.5, 4.25)
self.assertRaises(TypeError, complex, WithFloat(42))
self.assertRaises(TypeError, complex, WithFloat(42), 1.5)
self.assertRaises(TypeError, complex, 1.5, WithFloat(42))
self.assertRaises(TypeError, complex, WithFloat(None))
self.assertRaises(TypeError, complex, WithFloat(None), 1.5)
self.assertRaises(TypeError, complex, 1.5, WithFloat(None))
check(complex(WithIndex(42)), 42.0, 0.0)
check(complex(WithIndex(42), 1.5), 42.0, 1.5)
check(complex(1.5, WithIndex(42)), 1.5, 42.0)
self.assertRaises(OverflowError, complex, WithIndex(2**2000))
self.assertRaises(OverflowError, complex, WithIndex(2**2000), 1.5)
self.assertRaises(OverflowError, complex, 1.5, WithIndex(2**2000))
self.assertRaises(TypeError, complex, WithIndex(None))
self.assertRaises(TypeError, complex, WithIndex(None), 1.5)
self.assertRaises(TypeError, complex, 1.5, WithIndex(None))
class MyInt:
def __int__(self):
return 42
self.assertRaises(TypeError, complex, MyInt())
self.assertRaises(TypeError, complex, MyInt(), 1.5)
self.assertRaises(TypeError, complex, 1.5, MyInt())
class complex0(complex):
"""Test usage of __complex__() when inheriting from 'complex'"""
def __complex__(self):
return 42j
class complex1(complex):
"""Test usage of __complex__() with a __new__() method"""
def __new__(self, value=0j):
return complex.__new__(self, 2*value)
def __complex__(self):
return self
class complex2(complex):
"""Make sure that __complex__() calls fail if anything other than a
complex is returned"""
def __complex__(self):
return None
check(complex(complex0(1j)), 0.0, 42.0)
with self.assertWarns(DeprecationWarning):
check(complex(complex1(1j)), 0.0, 2.0)
self.assertRaises(TypeError, complex, complex2(1j))
def test___complex__(self):
z = 3 + 4j
self.assertEqual(z.__complex__(), z)
self.assertEqual(type(z.__complex__()), complex)
z = ComplexSubclass(3 + 4j)
self.assertEqual(z.__complex__(), 3 + 4j)
self.assertEqual(type(z.__complex__()), complex)
@support.requires_IEEE_754
def test_constructor_special_numbers(self):
for x in 0.0, -0.0, INF, -INF, NAN:
for y in 0.0, -0.0, INF, -INF, NAN:
with self.subTest(x=x, y=y):
z = complex(x, y)
self.assertFloatsAreIdentical(z.real, x)
self.assertFloatsAreIdentical(z.imag, y)
z = ComplexSubclass(x, y)
self.assertIs(type(z), ComplexSubclass)
self.assertFloatsAreIdentical(z.real, x)
self.assertFloatsAreIdentical(z.imag, y)
z = complex(ComplexSubclass(x, y))
self.assertIs(type(z), complex)
self.assertFloatsAreIdentical(z.real, x)
self.assertFloatsAreIdentical(z.imag, y)
z = ComplexSubclass(complex(x, y))
self.assertIs(type(z), ComplexSubclass)
self.assertFloatsAreIdentical(z.real, x)
self.assertFloatsAreIdentical(z.imag, y)
def test_constructor_from_string(self):
def check(z, x, y):
self.assertIs(type(z), complex)
self.assertFloatsAreIdentical(z.real, x)
self.assertFloatsAreIdentical(z.imag, y)
check(complex("1"), 1.0, 0.0)
check(complex("1j"), 0.0, 1.0)
check(complex("-1"), -1.0, 0.0)
check(complex("+1"), 1.0, 0.0)
check(complex("1+2j"), 1.0, 2.0)
check(complex("(1+2j)"), 1.0, 2.0)
check(complex("(1.5+4.25j)"), 1.5, 4.25)
check(complex("4.25+1J"), 4.25, 1.0)
check(complex(" ( +4.25-6J )"), 4.25, -6.0)
check(complex(" ( +4.25-J )"), 4.25, -1.0)
check(complex(" ( +4.25+j )"), 4.25, 1.0)
check(complex("J"), 0.0, 1.0)
check(complex("( j )"), 0.0, 1.0)
check(complex("+J"), 0.0, 1.0)
check(complex("( -j)"), 0.0, -1.0)
check(complex('1-1j'), 1.0, -1.0)
check(complex('1J'), 0.0, 1.0)
check(complex('1e-500'), 0.0, 0.0)
check(complex('-1e-500j'), 0.0, -0.0)
check(complex('1e-500+1e-500j'), 0.0, 0.0)
check(complex('-1e-500+1e-500j'), -0.0, 0.0)
check(complex('1e-500-1e-500j'), 0.0, -0.0)
check(complex('-1e-500-1e-500j'), -0.0, -0.0)
# SF bug 543840: complex(string) accepts strings with \0
# Fixed in 2.3.
self.assertRaises(ValueError, complex, '1+1j\0j')
self.assertRaises(ValueError, complex, "")
self.assertRaises(ValueError, complex, "\0")
self.assertRaises(ValueError, complex, "3\09")
self.assertRaises(ValueError, complex, "1+")
self.assertRaises(ValueError, complex, "1+1j+1j")
self.assertRaises(ValueError, complex, "--")
self.assertRaises(ValueError, complex, "(1+2j")
self.assertRaises(ValueError, complex, "1+2j)")
self.assertRaises(ValueError, complex, "1+(2j)")
self.assertRaises(ValueError, complex, "(1+2j)123")
self.assertRaises(ValueError, complex, "x")
self.assertRaises(ValueError, complex, "1j+2")
self.assertRaises(ValueError, complex, "1e1ej")
self.assertRaises(ValueError, complex, "1e++1ej")
self.assertRaises(ValueError, complex, ")1+2j(")
# the following three are accepted by Python 2.6
self.assertRaises(ValueError, complex, "1..1j")
self.assertRaises(ValueError, complex, "1.11.1j")
self.assertRaises(ValueError, complex, "1e1.1j")
# check that complex accepts long unicode strings
self.assertIs(type(complex("1"*500)), complex)
# check whitespace processing
self.assertEqual(complex('\N{EM SPACE}(\N{EN SPACE}1+1j ) '), 1+1j)
# Invalid unicode string
# See bpo-34087
self.assertRaises(ValueError, complex, '\u3053\u3093\u306b\u3061\u306f')
def test_constructor_negative_nans_from_string(self):
self.assertEqual(copysign(1., complex("-nan").real), -1.)
self.assertEqual(copysign(1., complex("-nanj").imag), -1.)
self.assertEqual(copysign(1., complex("-nan-nanj").real), -1.)
self.assertEqual(copysign(1., complex("-nan-nanj").imag), -1.)
def test_underscores(self):
# check underscores
for lit in VALID_UNDERSCORE_LITERALS:
if not any(ch in lit for ch in 'xXoObB'):
self.assertEqual(complex(lit), eval(lit))
self.assertEqual(complex(lit), complex(lit.replace('_', '')))
for lit in INVALID_UNDERSCORE_LITERALS:
if lit in ('0_7', '09_99'): # octals are not recognized here
continue
if not any(ch in lit for ch in 'xXoObB'):
self.assertRaises(ValueError, complex, lit)
def test_from_number(self, cls=complex):
def eq(actual, expected):
self.assertEqual(actual, expected)
self.assertIs(type(actual), cls)
eq(cls.from_number(3.14), 3.14+0j)
eq(cls.from_number(3.14j), 3.14j)
eq(cls.from_number(314), 314.0+0j)
eq(cls.from_number(OtherComplexSubclass(3.14, 2.72)), 3.14+2.72j)
eq(cls.from_number(WithComplex(3.14+2.72j)), 3.14+2.72j)
eq(cls.from_number(WithFloat(3.14)), 3.14+0j)
eq(cls.from_number(WithIndex(314)), 314.0+0j)
cNAN = complex(NAN, NAN)
x = cls.from_number(cNAN)
self.assertTrue(x != x)
self.assertIs(type(x), cls)
if cls is complex:
self.assertIs(cls.from_number(cNAN), cNAN)
self.assertRaises(TypeError, cls.from_number, '3.14')
self.assertRaises(TypeError, cls.from_number, b'3.14')
self.assertRaises(TypeError, cls.from_number, MyInt(314))
self.assertRaises(TypeError, cls.from_number, {})
self.assertRaises(TypeError, cls.from_number)
def test_from_number_subclass(self):
self.test_from_number(ComplexSubclass)
def test_hash(self):
for x in range(-30, 30):
self.assertEqual(hash(x), hash(complex(x, 0)))
x /= 3.0 # now check against floating-point
self.assertEqual(hash(x), hash(complex(x, 0.)))
self.assertNotEqual(hash(2000005 - 1j), -1)
def test_abs(self):
nums = [complex(x/3., y/7.) for x in range(-9,9) for y in range(-9,9)]
for num in nums:
self.assertAlmostEqual((num.real**2 + num.imag**2) ** 0.5, abs(num))
self.assertRaises(OverflowError, abs, complex(DBL_MAX, DBL_MAX))
def test_repr_str(self):
def test(v, expected, test_fn=self.assertEqual):
test_fn(repr(v), expected)
test_fn(str(v), expected)
test(1+6j, '(1+6j)')
test(1-6j, '(1-6j)')
test(-(1+0j), '(-1+-0j)', test_fn=self.assertNotEqual)
test(complex(1., INF), "(1+infj)")
test(complex(1., -INF), "(1-infj)")
test(complex(INF, 1), "(inf+1j)")
test(complex(-INF, INF), "(-inf+infj)")
test(complex(NAN, 1), "(nan+1j)")
test(complex(1, NAN), "(1+nanj)")
test(complex(NAN, NAN), "(nan+nanj)")
test(complex(-NAN, -NAN), "(nan+nanj)")
test(complex(0, INF), "infj")
test(complex(0, -INF), "-infj")
test(complex(0, NAN), "nanj")
self.assertEqual(1-6j,complex(repr(1-6j)))
self.assertEqual(1+6j,complex(repr(1+6j)))
self.assertEqual(-6j,complex(repr(-6j)))
self.assertEqual(6j,complex(repr(6j)))
@support.requires_IEEE_754
def test_negative_zero_repr_str(self):
def test(v, expected, test_fn=self.assertEqual):
test_fn(repr(v), expected)
test_fn(str(v), expected)
test(complex(0., 1.), "1j")
test(complex(-0., 1.), "(-0+1j)")
test(complex(0., -1.), "-1j")
test(complex(-0., -1.), "(-0-1j)")
test(complex(0., 0.), "0j")
test(complex(0., -0.), "-0j")
test(complex(-0., 0.), "(-0+0j)")
test(complex(-0., -0.), "(-0-0j)")
def test_pos(self):
self.assertEqual(+(1+6j), 1+6j)
self.assertEqual(+ComplexSubclass(1, 6), 1+6j)
self.assertIs(type(+ComplexSubclass(1, 6)), complex)
def test_neg(self):
self.assertEqual(-(1+6j), -1-6j)
def test_getnewargs(self):
self.assertEqual((1+2j).__getnewargs__(), (1.0, 2.0))
self.assertEqual((1-2j).__getnewargs__(), (1.0, -2.0))
self.assertEqual((2j).__getnewargs__(), (0.0, 2.0))
self.assertEqual((-0j).__getnewargs__(), (0.0, -0.0))
self.assertEqual(complex(0, INF).__getnewargs__(), (0.0, INF))
self.assertEqual(complex(INF, 0).__getnewargs__(), (INF, 0.0))
@support.requires_IEEE_754
def test_plus_minus_0j(self):
# test that -0j and 0j literals are not identified
z1, z2 = 0j, -0j
self.assertFloatsAreIdentical(z1.imag, 0.0)
self.assertFloatsAreIdentical(z2.imag, -0.0)
@support.requires_IEEE_754
def test_negated_imaginary_literal(self):
z0 = -0j
z1 = -7j
z2 = -1e1000j
# Note: In versions of Python < 3.2, a negated imaginary literal
# accidentally ended up with real part 0.0 instead of -0.0, thanks to a
# modification during CST -> AST translation (see issue #9011). That's
# fixed in Python 3.2.
self.assertFloatsAreIdentical(z0.real, -0.0)
self.assertFloatsAreIdentical(z0.imag, -0.0)
self.assertFloatsAreIdentical(z1.real, -0.0)
self.assertFloatsAreIdentical(z1.imag, -7.0)
self.assertFloatsAreIdentical(z2.real, -0.0)
self.assertFloatsAreIdentical(z2.imag, -INF)
@support.requires_IEEE_754
def test_overflow(self):
self.assertEqual(complex("1e500"), complex(INF, 0.0))
self.assertEqual(complex("-1e500j"), complex(0.0, -INF))
self.assertEqual(complex("-1e500+1.8e308j"), complex(-INF, INF))
@support.requires_IEEE_754
def test_repr_roundtrip(self):
vals = [0.0, 1e-500, 1e-315, 1e-200, 0.0123, 3.1415, 1e50, INF, NAN]
vals += [-v for v in vals]
# complex(repr(z)) should recover z exactly, even for complex
# numbers involving an infinity, nan, or negative zero
for x in vals:
for y in vals:
z = complex(x, y)
roundtrip = complex(repr(z))
self.assertComplexesAreIdentical(z, roundtrip)
# if we predefine some constants, then eval(repr(z)) should
# also work, except that it might change the sign of zeros
inf, nan = float('inf'), float('nan')
infj, nanj = complex(0.0, inf), complex(0.0, nan)
for x in vals:
for y in vals:
z = complex(x, y)
roundtrip = eval(repr(z))
# adding 0.0 has no effect beside changing -0.0 to 0.0
self.assertFloatsAreIdentical(0.0 + z.real,
0.0 + roundtrip.real)
self.assertFloatsAreIdentical(0.0 + z.imag,
0.0 + roundtrip.imag)
def test_format(self):
# empty format string is same as str()
self.assertEqual(format(1+3j, ''), str(1+3j))
self.assertEqual(format(1.5+3.5j, ''), str(1.5+3.5j))
self.assertEqual(format(3j, ''), str(3j))
self.assertEqual(format(3.2j, ''), str(3.2j))
self.assertEqual(format(3+0j, ''), str(3+0j))
self.assertEqual(format(3.2+0j, ''), str(3.2+0j))
# empty presentation type should still be analogous to str,
# even when format string is nonempty (issue #5920).
self.assertEqual(format(3.2+0j, '-'), str(3.2+0j))
self.assertEqual(format(3.2+0j, '<'), str(3.2+0j))
z = 4/7. - 100j/7.
self.assertEqual(format(z, ''), str(z))
self.assertEqual(format(z, '-'), str(z))
self.assertEqual(format(z, '<'), str(z))
self.assertEqual(format(z, '10'), str(z))
z = complex(0.0, 3.0)
self.assertEqual(format(z, ''), str(z))
self.assertEqual(format(z, '-'), str(z))
self.assertEqual(format(z, '<'), str(z))
self.assertEqual(format(z, '2'), str(z))
z = complex(-0.0, 2.0)
self.assertEqual(format(z, ''), str(z))
self.assertEqual(format(z, '-'), str(z))
self.assertEqual(format(z, '<'), str(z))
self.assertEqual(format(z, '3'), str(z))
self.assertEqual(format(1+3j, 'g'), '1+3j')
self.assertEqual(format(3j, 'g'), '0+3j')
self.assertEqual(format(1.5+3.5j, 'g'), '1.5+3.5j')
self.assertEqual(format(1.5+3.5j, '+g'), '+1.5+3.5j')
self.assertEqual(format(1.5-3.5j, '+g'), '+1.5-3.5j')
self.assertEqual(format(1.5-3.5j, '-g'), '1.5-3.5j')
self.assertEqual(format(1.5+3.5j, ' g'), ' 1.5+3.5j')
self.assertEqual(format(1.5-3.5j, ' g'), ' 1.5-3.5j')
self.assertEqual(format(-1.5+3.5j, ' g'), '-1.5+3.5j')
self.assertEqual(format(-1.5-3.5j, ' g'), '-1.5-3.5j')
self.assertEqual(format(-1.5-3.5e-20j, 'g'), '-1.5-3.5e-20j')
self.assertEqual(format(-1.5-3.5j, 'f'), '-1.500000-3.500000j')
self.assertEqual(format(-1.5-3.5j, 'F'), '-1.500000-3.500000j')
self.assertEqual(format(-1.5-3.5j, 'e'), '-1.500000e+00-3.500000e+00j')
self.assertEqual(format(-1.5-3.5j, '.2e'), '-1.50e+00-3.50e+00j')
self.assertEqual(format(-1.5-3.5j, '.2E'), '-1.50E+00-3.50E+00j')
self.assertEqual(format(-1.5e10-3.5e5j, '.2G'), '-1.5E+10-3.5E+05j')
self.assertEqual(format(1.5+3j, '<20g'), '1.5+3j ')
self.assertEqual(format(1.5+3j, '*<20g'), '1.5+3j**************')
self.assertEqual(format(1.5+3j, '>20g'), ' 1.5+3j')
self.assertEqual(format(1.5+3j, '^20g'), ' 1.5+3j ')
self.assertEqual(format(1.5+3j, '<20'), '(1.5+3j) ')
self.assertEqual(format(1.5+3j, '>20'), ' (1.5+3j)')
self.assertEqual(format(1.5+3j, '^20'), ' (1.5+3j) ')
self.assertEqual(format(1.123-3.123j, '^20.2'), ' (1.1-3.1j) ')
self.assertEqual(format(1.5+3j, '20.2f'), ' 1.50+3.00j')
self.assertEqual(format(1.5+3j, '>20.2f'), ' 1.50+3.00j')
self.assertEqual(format(1.5+3j, '<20.2f'), '1.50+3.00j ')
self.assertEqual(format(1.5e20+3j, '<20.2f'), '150000000000000000000.00+3.00j')
self.assertEqual(format(1.5e20+3j, '>40.2f'), ' 150000000000000000000.00+3.00j')
self.assertEqual(format(1.5e20+3j, '^40,.2f'), ' 150,000,000,000,000,000,000.00+3.00j ')
self.assertEqual(format(1.5e21+3j, '^40,.2f'), ' 1,500,000,000,000,000,000,000.00+3.00j ')
self.assertEqual(format(1.5e21+3000j, ',.2f'), '1,500,000,000,000,000,000,000.00+3,000.00j')
# Issue 7094: Alternate formatting (specified by #)
self.assertEqual(format(1+1j, '.0e'), '1e+00+1e+00j')
self.assertEqual(format(1+1j, '#.0e'), '1.e+00+1.e+00j')
self.assertEqual(format(1+1j, '.0f'), '1+1j')
self.assertEqual(format(1+1j, '#.0f'), '1.+1.j')
self.assertEqual(format(1.1+1.1j, 'g'), '1.1+1.1j')
self.assertEqual(format(1.1+1.1j, '#g'), '1.10000+1.10000j')
# Alternate doesn't make a difference for these, they format the same with or without it
self.assertEqual(format(1+1j, '.1e'), '1.0e+00+1.0e+00j')
self.assertEqual(format(1+1j, '#.1e'), '1.0e+00+1.0e+00j')
self.assertEqual(format(1+1j, '.1f'), '1.0+1.0j')
self.assertEqual(format(1+1j, '#.1f'), '1.0+1.0j')
# Misc. other alternate tests
self.assertEqual(format((-1.5+0.5j), '#f'), '-1.500000+0.500000j')
self.assertEqual(format((-1.5+0.5j), '#.0f'), '-2.+0.j')
self.assertEqual(format((-1.5+0.5j), '#e'), '-1.500000e+00+5.000000e-01j')
self.assertEqual(format((-1.5+0.5j), '#.0e'), '-2.e+00+5.e-01j')
self.assertEqual(format((-1.5+0.5j), '#g'), '-1.50000+0.500000j')
self.assertEqual(format((-1.5+0.5j), '.0g'), '-2+0.5j')
self.assertEqual(format((-1.5+0.5j), '#.0g'), '-2.+0.5j')
# zero padding is invalid
self.assertRaises(ValueError, (1.5+0.5j).__format__, '010f')
# '=' alignment is invalid
self.assertRaises(ValueError, (1.5+3j).__format__, '=20')
# integer presentation types are an error
for t in 'bcdoxX':
self.assertRaises(ValueError, (1.5+0.5j).__format__, t)
# make sure everything works in ''.format()
self.assertEqual('*{0:.3f}*'.format(3.14159+2.71828j), '*3.142+2.718j*')
# issue 3382
self.assertEqual(format(complex(NAN, NAN), 'f'), 'nan+nanj')
self.assertEqual(format(complex(1, NAN), 'f'), '1.000000+nanj')
self.assertEqual(format(complex(NAN, 1), 'f'), 'nan+1.000000j')
self.assertEqual(format(complex(NAN, -1), 'f'), 'nan-1.000000j')
self.assertEqual(format(complex(NAN, NAN), 'F'), 'NAN+NANj')
self.assertEqual(format(complex(1, NAN), 'F'), '1.000000+NANj')
self.assertEqual(format(complex(NAN, 1), 'F'), 'NAN+1.000000j')
self.assertEqual(format(complex(NAN, -1), 'F'), 'NAN-1.000000j')
self.assertEqual(format(complex(INF, INF), 'f'), 'inf+infj')
self.assertEqual(format(complex(1, INF), 'f'), '1.000000+infj')
self.assertEqual(format(complex(INF, 1), 'f'), 'inf+1.000000j')
self.assertEqual(format(complex(INF, -1), 'f'), 'inf-1.000000j')
self.assertEqual(format(complex(INF, INF), 'F'), 'INF+INFj')
self.assertEqual(format(complex(1, INF), 'F'), '1.000000+INFj')
self.assertEqual(format(complex(INF, 1), 'F'), 'INF+1.000000j')
self.assertEqual(format(complex(INF, -1), 'F'), 'INF-1.000000j')
if __name__ == "__main__":
unittest.main()