Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6649fa4

Browse files
committed
Make sure that complex parsing code and corresponding tests
match for 2.7 and 3.1, and that 3.1 continues to accept complex('j') and complex('4-j')
1 parent c00b5ef commit 6649fa4

2 files changed

Lines changed: 98 additions & 27 deletions

File tree

Lib/test/test_complex.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,15 @@ def __complex__(self): return self.value
227227
self.assertAlmostEqual(complex("(1.3+2.2j)"), 1.3+2.2j)
228228
self.assertAlmostEqual(complex("3.14+1J"), 3.14+1j)
229229
self.assertAlmostEqual(complex(" ( +3.14-6J )"), 3.14-6j)
230+
self.assertAlmostEqual(complex(" ( +3.14-J )"), 3.14-1j)
231+
self.assertAlmostEqual(complex(" ( +3.14+j )"), 3.14+1j)
232+
self.assertAlmostEqual(complex("J"), 1j)
233+
self.assertAlmostEqual(complex("( j )"), 1j)
234+
self.assertAlmostEqual(complex("+J"), 1j)
235+
self.assertAlmostEqual(complex("( -j)"), -1j)
236+
self.assertAlmostEqual(complex('1e-500'), 0.0 + 0.0j)
237+
self.assertAlmostEqual(complex('-1e-500j'), 0.0 - 0.0j)
238+
self.assertAlmostEqual(complex('-1e-500+1e-500j'), -0.0 + 0.0j)
230239

231240
class complex2(complex): pass
232241
self.assertAlmostEqual(complex(complex2(1+1j)), 1+1j)
@@ -277,11 +286,14 @@ def split_zeros(x):
277286
self.assertRaises(ValueError, complex, "(1+2j)123")
278287
self.assertRaises(ValueError, complex, "1"*500)
279288
self.assertRaises(ValueError, complex, "x")
280-
self.assertRaises(ValueError, complex, "J")
281289
self.assertRaises(ValueError, complex, "1j+2")
282290
self.assertRaises(ValueError, complex, "1e1ej")
283291
self.assertRaises(ValueError, complex, "1e++1ej")
284292
self.assertRaises(ValueError, complex, ")1+2j(")
293+
# the following three are accepted by Python 2.6
294+
self.assertRaises(ValueError, complex, "1..1j")
295+
self.assertRaises(ValueError, complex, "1.11.1j")
296+
self.assertRaises(ValueError, complex, "1e1.1j")
285297

286298
class EvilExc(Exception):
287299
pass

Objects/complexobject.c

Lines changed: 85 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -760,50 +760,109 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v)
760760
s++;
761761
}
762762

763-
/* get float---might be real or imaginary part */
763+
/* a valid complex string usually takes one of the three forms:
764+
765+
<float> - real part only
766+
<float>j - imaginary part only
767+
<float><signed-float>j - real and imaginary parts
768+
769+
where <float> represents any numeric string that's accepted by the
770+
float constructor (including 'nan', 'inf', 'infinity', etc.), and
771+
<signed-float> is any string of the form <float> whose first
772+
character is '+' or '-'.
773+
774+
For backwards compatibility, the extra forms
775+
776+
<float><sign>j
777+
<sign>j
778+
j
779+
780+
are also accepted, though support for these forms may be removed from
781+
a future version of Python.
782+
*/
783+
784+
/* first look for forms starting with <float> */
764785
z = PyOS_ascii_strtod(s, &end);
765-
if (end == s)
766-
goto error;
767-
s = end;
768-
if (*s == '+' || *s == '-') {
769-
/* we've got a real part *and* an imaginary part */
770-
x = z;
771-
y = PyOS_ascii_strtod(s, &end);
772-
if (end == s || !(*end == 'j' || *end == 'J'))
773-
goto error;
774-
s = ++end;
786+
if (end == s && errno == ENOMEM)
787+
return PyErr_NoMemory();
788+
if (errno == ERANGE && fabs(z) >= 1.0)
789+
goto overflow;
790+
791+
if (end != s) {
792+
/* all 4 forms starting with <float> land here */
793+
s = end;
794+
if (*s == '+' || *s == '-') {
795+
/* <float><signed-float>j | <float><sign>j */
796+
x = z;
797+
y = PyOS_ascii_strtod(s, &end);
798+
if (end == s && errno == ENOMEM)
799+
return PyErr_NoMemory();
800+
if (errno == ERANGE && fabs(z) >= 1.0)
801+
goto overflow;
802+
if (end != s)
803+
/* <float><signed-float>j */
804+
s = end;
805+
else {
806+
/* <float><sign>j */
807+
y = *s == '+' ? 1.0 : -1.0;
808+
s++;
809+
}
810+
if (!(*s == 'j' || *s == 'J'))
811+
goto parse_error;
812+
s++;
813+
}
814+
else if (*s == 'j' || *s == 'J') {
815+
/* <float>j */
816+
s++;
817+
y = z;
818+
}
819+
else
820+
/* <float> */
821+
x = z;
775822
}
776-
else if (*s == 'j' || *s == 'J') {
777-
/* no real part; z was the imaginary part */
823+
else {
824+
/* not starting with <float>; must be <sign>j or j */
825+
if (*s == '+' || *s == '-') {
826+
/* <sign>j */
827+
y = *s == '+' ? 1.0 : -1.0;
828+
s++;
829+
}
830+
else
831+
/* j */
832+
y = 1.0;
833+
if (!(*s == 'j' || *s == 'J'))
834+
goto parse_error;
778835
s++;
779-
y = z;
780836
}
781-
else
782-
/* no imaginary part */
783-
x = z;
784837

785838
/* trailing whitespace and closing bracket */
786839
while (*s && isspace(Py_CHARMASK(*s)))
787840
s++;
788-
if (got_bracket && *s == ')') {
789-
got_bracket = 0;
841+
if (got_bracket) {
842+
/* if there was an opening parenthesis, then the corresponding
843+
closing parenthesis should be right here */
844+
if (*s != ')')
845+
goto parse_error;
790846
s++;
791847
while (*s && isspace(Py_CHARMASK(*s)))
792-
s++;
848+
s++;
793849
}
850+
794851
/* we should now be at the end of the string */
795-
if (s-start != len || got_bracket)
796-
goto error;
852+
if (s-start != len)
853+
goto parse_error;
797854

798855
return complex_subtype_from_doubles(type, x, y);
799856

800-
error:
801-
/* check for PyOS_ascii_strtod failure due to lack of memory */
802-
if (errno == ENOMEM)
803-
return PyErr_NoMemory();
857+
parse_error:
804858
PyErr_SetString(PyExc_ValueError,
805859
"complex() arg is a malformed string");
806860
return NULL;
861+
862+
overflow:
863+
PyErr_SetString(PyExc_OverflowError,
864+
"complex() arg overflow");
865+
return NULL;
807866
}
808867

809868
static PyObject *

0 commit comments

Comments
 (0)