Skip to content

Commit 3450b30

Browse files
committed
cleanup printf-style implementation
1 parent 3e4c5e8 commit 3450b30

File tree

4 files changed

+46
-39
lines changed

4 files changed

+46
-39
lines changed

Lib/test/test_float.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@ def test_format(self):
703703
# hexadecimal format
704704
x = float.fromhex('0x0.0030p+0')
705705
self.assertEqual(format(x, 'x'), '1.8p-11')
706+
x = float.fromhex('0x0.1p-1022') # subnormal
707+
self.assertEqual(format(x, 'x'), '0.1p-1022')
706708
x = float.fromhex('0x0.0040p+0')
707709
self.assertEqual(format(x, 'x'), '1p-10')
708710
self.assertEqual(format(x, '>10x'), ' 1p-10')

Lib/test/test_format.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,8 @@ def test_common_format(self):
293293
"%x format: an integer or float is required, not str")
294294
test_exc_common('%d', 1j, TypeError,
295295
"%d format: a real number is required, not complex")
296+
test_exc_common('%x', 1j, TypeError,
297+
"%x format: an integer or float is required, not complex")
296298

297299
def test_str_format(self):
298300
testformat("%r", "\u0378", "'\\u0378'") # non printable

Objects/bytesobject.c

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -466,30 +466,13 @@ formatlong(PyObject *v, int flags, int prec, int type)
466466
Py_DECREF(iobj);
467467
return result;
468468
}
469-
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
470-
if (type == 'x' || type == 'X') {
471-
PyErr_Clear();
472-
473-
PyObject *fobj = PyNumber_Float(v);
474-
if (!fobj) {
475-
goto wrongtype;
476-
}
477-
formatfloat(fobj, flags, prec, type, &result, NULL, NULL);
478-
if (!result) {
479-
return NULL;
480-
}
481-
return PyUnicode_FromEncodedObject(result, NULL, NULL);
482-
}
483-
}
484-
else {
469+
if (!PyErr_ExceptionMatches(PyExc_TypeError))
485470
return NULL;
486-
}
487471
}
488-
wrongtype:
489472
PyErr_Format(PyExc_TypeError,
490473
"%%%c format: %s is required, not %.200s", type,
491-
(type == 'x' || type == 'X') ?
492-
"an integer or float" : type == 'o' ? "an integer": "a real number",
474+
(type == 'o' || type == 'x' || type == 'X') ? "an integer"
475+
: "a real number",
493476
Py_TYPE(v)->tp_name);
494477
return NULL;
495478
}
@@ -886,8 +869,24 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
886869
}
887870

888871
temp = formatlong(v, flags, prec, c);
889-
if (!temp)
872+
if (!temp) {
873+
if ((c == 'x' || c == 'X') &&
874+
PyErr_ExceptionMatches(PyExc_TypeError))
875+
{
876+
PyErr_Clear();
877+
if (PyNumber_Check(v)) {
878+
PyObject *fobj = PyNumber_Float(v);
879+
if (fobj) {
880+
v = fobj;
881+
goto dofloats;
882+
}
883+
}
884+
PyErr_Format(PyExc_TypeError,
885+
"%%%c format: an integer or float is required, not %.200s",
886+
c, Py_TYPE(v)->tp_name);
887+
}
890888
goto error;
889+
}
891890
assert(PyUnicode_IS_ASCII(temp));
892891
pbuf = (const char *)PyUnicode_1BYTE_DATA(temp);
893892
len = PyUnicode_GET_LENGTH(temp);
@@ -896,6 +895,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
896895
fill = '0';
897896
break;
898897

898+
dofloats:
899899
case 'e':
900900
case 'E':
901901
case 'f':

Objects/unicodeobject.c

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13901,18 +13901,8 @@ mainformatlong(PyObject *v,
1390113901
iobj = PyNumber_Long(v);
1390213902
}
1390313903
if (iobj == NULL ) {
13904-
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
13905-
if (type == 'x' || type == 'X') {
13906-
PyErr_Clear();
13907-
13908-
PyObject *fobj = PyNumber_Float(v);
13909-
if (!fobj) {
13910-
goto wrongtype;
13911-
}
13912-
return formatfloat(fobj, arg, p_output, NULL);
13913-
}
13904+
if (PyErr_ExceptionMatches(PyExc_TypeError))
1391413905
goto wrongtype;
13915-
}
1391613906
return -1;
1391713907
}
1391813908
assert(PyLong_Check(iobj));
@@ -13967,15 +13957,10 @@ mainformatlong(PyObject *v,
1396713957
switch(type)
1396813958
{
1396913959
case 'o':
13970-
PyErr_Format(PyExc_TypeError,
13971-
"%%%c format: an integer is required, "
13972-
"not %.200s",
13973-
type, Py_TYPE(v)->tp_name);
13974-
break;
1397513960
case 'x':
1397613961
case 'X':
1397713962
PyErr_Format(PyExc_TypeError,
13978-
"%%%c format: an integer or float is required, "
13963+
"%%%c format: an integer is required, "
1397913964
"not %.200s",
1398013965
type, Py_TYPE(v)->tp_name);
1398113966
break;
@@ -14266,12 +14251,30 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx,
1426614251
case 'X':
1426714252
{
1426814253
int ret = mainformatlong(v, arg, p_str, writer);
14269-
if (ret != 0)
14254+
if (ret != 0) {
14255+
if (ret == -1 && (arg->ch == 'x' || arg->ch == 'X') &&
14256+
PyErr_ExceptionMatches(PyExc_TypeError))
14257+
{
14258+
PyErr_Clear();
14259+
if (PyNumber_Check(v)) {
14260+
PyObject *fobj = PyNumber_Float(v);
14261+
if (fobj) {
14262+
v = fobj;
14263+
goto dofloats;
14264+
}
14265+
}
14266+
PyErr_Format(PyExc_TypeError,
14267+
"%%%c format: an integer or float is required, "
14268+
"not %.200s",
14269+
arg->ch, Py_TYPE(v)->tp_name);
14270+
}
1427014271
return ret;
14272+
}
1427114273
arg->sign = 1;
1427214274
break;
1427314275
}
1427414276

14277+
dofloats:
1427514278
case 'e':
1427614279
case 'E':
1427714280
case 'f':

0 commit comments

Comments
 (0)