bpo-31979: Simplify transforming decimals to ASCII (#4336) · pythoncapi/cpython@9b6c60c · GitHub
Skip to content

Commit 9b6c60c

Browse files
bpo-31979: Simplify transforming decimals to ASCII (python#4336)
in int(), float() and complex() parsers. This also speeds up parsing non-ASCII numbers by around 20%.
1 parent ce12629 commit 9b6c60c

7 files changed

Lines changed: 63 additions & 139 deletions

File tree

Include/unicodeobject.h

Lines changed: 7 additions & 9 deletions

Lib/test/test_float.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def test_float(self):
5151
self.assertRaises(TypeError, float, {})
5252
self.assertRaisesRegex(TypeError, "not 'dict'", float, {})
5353
# Lone surrogate
54-
self.assertRaises(UnicodeEncodeError, float, '\uD8F0')
54+
self.assertRaises(ValueError, float, '\uD8F0')
5555
# check that we don't accept alternate exponent markers
5656
self.assertRaises(ValueError, float, "-1.7d29")
5757
self.assertRaises(ValueError, float, "3D-14")

Lib/test/test_unicode.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,11 +2068,14 @@ def test_codecs_errors(self):
20682068
# Error handling (wrong arguments)
20692069
self.assertRaises(TypeError, "hello".encode, 42, 42, 42)
20702070

2071-
# Error handling (lone surrogate in PyUnicode_TransformDecimalToASCII())
2072-
self.assertRaises(UnicodeError, float, "\ud800")
2073-
self.assertRaises(UnicodeError, float, "\udf00")
2074-
self.assertRaises(UnicodeError, complex, "\ud800")
2075-
self.assertRaises(UnicodeError, complex, "\udf00")
2071+
# Error handling (lone surrogate in
2072+
# _PyUnicode_TransformDecimalAndSpaceToASCII())
2073+
self.assertRaises(ValueError, int, "\ud800")
2074+
self.assertRaises(ValueError, int, "\udf00")
2075+
self.assertRaises(ValueError, float, "\ud800")
2076+
self.assertRaises(ValueError, float, "\udf00")
2077+
self.assertRaises(ValueError, complex, "\ud800")
2078+
self.assertRaises(ValueError, complex, "\udf00")
20762079

20772080
def test_codecs(self):
20782081
# Encoding

Objects/complexobject.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -914,10 +914,10 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v)
914914
if (s_buffer == NULL) {
915915
return NULL;
916916
}
917+
assert(PyUnicode_IS_ASCII(s_buffer));
918+
/* Simply get a pointer to existing ASCII characters. */
917919
s = PyUnicode_AsUTF8AndSize(s_buffer, &len);
918-
if (s == NULL) {
919-
goto exit;
920-
}
920+
assert(s != NULL);
921921
}
922922
else {
923923
PyErr_Format(PyExc_TypeError,
@@ -928,7 +928,6 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v)
928928

929929
result = _Py_string_to_number_with_underscores(s, len, "complex", v, type,
930930
complex_from_string_inner);
931-
exit:
932931
Py_DECREF(s_buffer);
933932
return result;
934933
}

Objects/floatobject.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,10 @@ PyFloat_FromString(PyObject *v)
176176
s_buffer = _PyUnicode_TransformDecimalAndSpaceToASCII(v);
177177
if (s_buffer == NULL)
178178
return NULL;
179+
assert(PyUnicode_IS_ASCII(s_buffer));
180+
/* Simply get a pointer to existing ASCII characters. */
179181
s = PyUnicode_AsUTF8AndSize(s_buffer, &len);
180-
if (s == NULL) {
181-
Py_DECREF(s_buffer);
182-
return NULL;
183-
}
182+
assert(s != NULL);
184183
}
185184
else if (PyBytes_Check(v)) {
186185
s = PyBytes_AS_STRING(v);

Objects/longobject.c

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,21 +2509,18 @@ PyLong_FromUnicodeObject(PyObject *u, int base)
25092509
asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u);
25102510
if (asciidig == NULL)
25112511
return NULL;
2512+
assert(PyUnicode_IS_ASCII(asciidig));
2513+
/* Simply get a pointer to existing ASCII characters. */
25122514
buffer = PyUnicode_AsUTF8AndSize(asciidig, &buflen);
2513-
if (buffer == NULL) {
2514-
Py_DECREF(asciidig);
2515-
if (!PyErr_ExceptionMatches(PyExc_UnicodeEncodeError))
2516-
return NULL;
2517-
}
2518-
else {
2519-
result = PyLong_FromString(buffer, &end, base);
2520-
if (end == NULL || (result != NULL && end == buffer + buflen)) {
2521-
Py_DECREF(asciidig);
2522-
return result;
2523-
}
2515+
assert(buffer != NULL);
2516+
2517+
result = PyLong_FromString(buffer, &end, base);
2518+
if (end == NULL || (result != NULL && end == buffer + buflen)) {
25242519
Py_DECREF(asciidig);
2525-
Py_XDECREF(result);
2520+
return result;
25262521
}
2522+
Py_DECREF(asciidig);
2523+
Py_XDECREF(result);
25272524
PyErr_Format(PyExc_ValueError,
25282525
"invalid literal for int() with base %d: %.200R",
25292526
base, u);

Objects/unicodeobject.c

Lines changed: 32 additions & 104 deletions

0 commit comments

Comments
 (0)