Skip to content

Commit fbc3b57

Browse files
author
facundo.batista
committed
Issue 1742669. Now %d accepts very big float numbers. Thanks Gabriel Genellina. git-svn-id: http://svn.python.org/projects/python/trunk@61041 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 498ba14 commit fbc3b57

4 files changed

Lines changed: 118 additions & 32 deletions

File tree

Lib/test/string_tests.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,14 @@ def test_formatting(self):
10331033
# unicode raises ValueError, str raises OverflowError
10341034
self.checkraises((ValueError, OverflowError), '%c', '__mod__', ordinal)
10351035

1036+
longvalue = sys.maxint + 10L
1037+
slongvalue = str(longvalue)
1038+
if slongvalue[-1] in ("L","l"): slongvalue = slongvalue[:-1]
10361039
self.checkequal(' 42', '%3ld', '__mod__', 42)
1040+
self.checkequal('42', '%d', '__mod__', 42L)
1041+
self.checkequal('42', '%d', '__mod__', 42.0)
1042+
self.checkequal(slongvalue, '%d', '__mod__', longvalue)
1043+
self.checkcall('%d', '__mod__', float(longvalue))
10371044
self.checkequal('0042.00', '%07.2f', '__mod__', 42)
10381045
self.checkequal('0042.00', '%07.2F', '__mod__', 42)
10391046

@@ -1043,6 +1050,8 @@ def test_formatting(self):
10431050
self.checkraises(TypeError, '%c', '__mod__', (None,))
10441051
self.checkraises(ValueError, '%(foo', '__mod__', {})
10451052
self.checkraises(TypeError, '%(foo)s %(bar)s', '__mod__', ('foo', 42))
1053+
self.checkraises(TypeError, '%d', '__mod__', "42") # not numeric
1054+
self.checkraises(TypeError, '%d', '__mod__', (42+0j)) # no int/long conversion provided
10461055

10471056
# argument names with properly nested brackets are supported
10481057
self.checkequal('bar', '%((foo))s', '__mod__', {'(foo)': 'bar'})

Lib/test/test_format.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
overflowok = 1
1212
overflowrequired = 0
1313

14-
def testformat(formatstr, args, output=None):
14+
def testformat(formatstr, args, output=None, limit=None):
1515
if verbose:
1616
if output:
1717
print "%s %% %s =? %s ..." %\
@@ -31,7 +31,18 @@ def testformat(formatstr, args, output=None):
3131
print 'no'
3232
print "overflow expected on %s %% %s" % \
3333
(repr(formatstr), repr(args))
34-
elif output and result != output:
34+
elif output and limit is None and result != output:
35+
if verbose:
36+
print 'no'
37+
print "%s %% %s == %s != %s" % \
38+
(repr(formatstr), repr(args), repr(result), repr(output))
39+
# when 'limit' is specified, it determines how many characters
40+
# must match exactly; lengths must always match.
41+
# ex: limit=5, '12345678' matches '12345___'
42+
# (mainly for floating point format tests for which an exact match
43+
# can't be guaranteed due to rounding and representation errors)
44+
elif output and limit is not None and (
45+
len(result)!=len(output) or result[:limit]!=output[:limit]):
3546
if verbose:
3647
print 'no'
3748
print "%s %% %s == %s != %s" % \
@@ -98,6 +109,7 @@ def testboth(formatstr, *args):
98109
testboth("%.30d", big, "123456789012345678901234567890")
99110
testboth("%.31d", big, "0123456789012345678901234567890")
100111
testboth("%32.31d", big, " 0123456789012345678901234567890")
112+
testboth("%d", float(big), "123456________________________", 6)
101113

102114
big = 0x1234567890abcdef12345L # 21 hex digits
103115
testboth("%x", big, "1234567890abcdef12345")
@@ -135,6 +147,7 @@ def testboth(formatstr, *args):
135147
testboth("%#+027.23X", big, "+0X0001234567890ABCDEF12345")
136148
# same, except no 0 flag
137149
testboth("%#+27.23X", big, " +0X001234567890ABCDEF12345")
150+
testboth("%x", float(big), "123456_______________", 6)
138151

139152
big = 012345670123456701234567012345670L # 32 octal digits
140153
testboth("%o", big, "12345670123456701234567012345670")
@@ -175,16 +188,19 @@ def testboth(formatstr, *args):
175188
testboth("%034.33o", big, "0012345670123456701234567012345670")
176189
# base marker shouldn't change that
177190
testboth("%0#34.33o", big, "0012345670123456701234567012345670")
191+
testboth("%o", float(big), "123456__________________________", 6)
178192

179193
# Some small ints, in both Python int and long flavors).
180194
testboth("%d", 42, "42")
181195
testboth("%d", -42, "-42")
182196
testboth("%d", 42L, "42")
183197
testboth("%d", -42L, "-42")
198+
testboth("%d", 42.0, "42")
184199
testboth("%#x", 1, "0x1")
185200
testboth("%#x", 1L, "0x1")
186201
testboth("%#X", 1, "0X1")
187202
testboth("%#X", 1L, "0X1")
203+
testboth("%#x", 1.0, "0x1")
188204
testboth("%#o", 1, "01")
189205
testboth("%#o", 1L, "01")
190206
testboth("%#o", 0, "0")
@@ -202,11 +218,13 @@ def testboth(formatstr, *args):
202218
testboth("%x", -0x42, "-42")
203219
testboth("%x", 0x42L, "42")
204220
testboth("%x", -0x42L, "-42")
221+
testboth("%x", float(0x42), "42")
205222

206223
testboth("%o", 042, "42")
207224
testboth("%o", -042, "-42")
208225
testboth("%o", 042L, "42")
209226
testboth("%o", -042L, "-42")
227+
testboth("%o", float(042), "42")
210228

211229
# Test exception for unknown format characters
212230
if verbose:
@@ -235,7 +253,7 @@ def test_exc(formatstr, args, exception, excmsg):
235253
test_exc(unicode('abc %\u3000','raw-unicode-escape'), 1, ValueError,
236254
"unsupported format character '?' (0x3000) at index 5")
237255

238-
test_exc('%d', '1', TypeError, "int argument required, not str")
256+
test_exc('%d', '1', TypeError, "%d format: a number is required, not str")
239257
test_exc('%g', '1', TypeError, "float argument required, not str")
240258
test_exc('no format', '1', TypeError,
241259
"not all arguments converted during string formatting")

Objects/stringobject.c

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4585,6 +4585,7 @@ PyString_Format(PyObject *format, PyObject *args)
45854585
int prec = -1;
45864586
int c = '\0';
45874587
int fill;
4588+
int isnumok;
45884589
PyObject *v = NULL;
45894590
PyObject *temp = NULL;
45904591
char *pbuf;
@@ -4786,23 +4787,52 @@ PyString_Format(PyObject *format, PyObject *args)
47864787
case 'X':
47874788
if (c == 'i')
47884789
c = 'd';
4789-
if (PyLong_Check(v)) {
4790-
int ilen;
4791-
temp = _PyString_FormatLong(v, flags,
4792-
prec, c, &pbuf, &ilen);
4793-
len = ilen;
4794-
if (!temp)
4795-
goto error;
4796-
sign = 1;
4790+
isnumok = 0;
4791+
if (PyNumber_Check(v)) {
4792+
PyObject *iobj=NULL;
4793+
4794+
if (PyInt_Check(v) || (PyLong_Check(v))) {
4795+
iobj = v;
4796+
Py_INCREF(iobj);
4797+
}
4798+
else {
4799+
iobj = PyNumber_Int(v);
4800+
if (iobj==NULL) iobj = PyNumber_Long(v);
4801+
}
4802+
if (iobj!=NULL) {
4803+
if (PyInt_Check(iobj)) {
4804+
isnumok = 1;
4805+
pbuf = formatbuf;
4806+
len = formatint(pbuf,
4807+
sizeof(formatbuf),
4808+
flags, prec, c, iobj);
4809+
Py_DECREF(iobj);
4810+
if (len < 0)
4811+
goto error;
4812+
sign = 1;
4813+
}
4814+
else if (PyLong_Check(iobj)) {
4815+
int ilen;
4816+
4817+
isnumok = 1;
4818+
temp = _PyString_FormatLong(iobj, flags,
4819+
prec, c, &pbuf, &ilen);
4820+
Py_DECREF(iobj);
4821+
len = ilen;
4822+
if (!temp)
4823+
goto error;
4824+
sign = 1;
4825+
}
4826+
else {
4827+
Py_DECREF(iobj);
4828+
}
4829+
}
47974830
}
4798-
else {
4799-
pbuf = formatbuf;
4800-
len = formatint(pbuf,
4801-
sizeof(formatbuf),
4802-
flags, prec, c, v);
4803-
if (len < 0)
4804-
goto error;
4805-
sign = 1;
4831+
if (!isnumok) {
4832+
PyErr_Format(PyExc_TypeError,
4833+
"%%%c format: a number is required, "
4834+
"not %.200s", c, Py_TYPE(v)->tp_name);
4835+
goto error;
48064836
}
48074837
if (flags & F_ZERO)
48084838
fill = '0';

Objects/unicodeobject.c

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8334,6 +8334,7 @@ PyObject *PyUnicode_Format(PyObject *format,
83348334
int prec = -1;
83358335
Py_UNICODE c = '\0';
83368336
Py_UNICODE fill;
8337+
int isnumok;
83378338
PyObject *v = NULL;
83388339
PyObject *temp = NULL;
83398340
Py_UNICODE *pbuf;
@@ -8546,21 +8547,49 @@ PyObject *PyUnicode_Format(PyObject *format,
85468547
case 'X':
85478548
if (c == 'i')
85488549
c = 'd';
8549-
if (PyLong_Check(v)) {
8550-
temp = formatlong(v, flags, prec, c);
8551-
if (!temp)
8552-
goto onError;
8553-
pbuf = PyUnicode_AS_UNICODE(temp);
8554-
len = PyUnicode_GET_SIZE(temp);
8555-
sign = 1;
8550+
isnumok = 0;
8551+
if (PyNumber_Check(v)) {
8552+
PyObject *iobj=NULL;
8553+
8554+
if (PyInt_Check(v) || (PyLong_Check(v))) {
8555+
iobj = v;
8556+
Py_INCREF(iobj);
8557+
}
8558+
else {
8559+
iobj = PyNumber_Int(v);
8560+
if (iobj==NULL) iobj = PyNumber_Long(v);
8561+
}
8562+
if (iobj!=NULL) {
8563+
if (PyInt_Check(iobj)) {
8564+
isnumok = 1;
8565+
pbuf = formatbuf;
8566+
len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE),
8567+
flags, prec, c, iobj);
8568+
Py_DECREF(iobj);
8569+
if (len < 0)
8570+
goto onError;
8571+
sign = 1;
8572+
}
8573+
else if (PyLong_Check(iobj)) {
8574+
isnumok = 1;
8575+
temp = formatlong(iobj, flags, prec, c);
8576+
Py_DECREF(iobj);
8577+
if (!temp)
8578+
goto onError;
8579+
pbuf = PyUnicode_AS_UNICODE(temp);
8580+
len = PyUnicode_GET_SIZE(temp);
8581+
sign = 1;
8582+
}
8583+
else {
8584+
Py_DECREF(iobj);
8585+
}
8586+
}
85568587
}
8557-
else {
8558-
pbuf = formatbuf;
8559-
len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE),
8560-
flags, prec, c, v);
8561-
if (len < 0)
8588+
if (!isnumok) {
8589+
PyErr_Format(PyExc_TypeError,
8590+
"%%%c format: a number is required, "
8591+
"not %.200s", c, Py_TYPE(v)->tp_name);
85628592
goto onError;
8563-
sign = 1;
85648593
}
85658594
if (flags & F_ZERO)
85668595
fill = '0';

0 commit comments

Comments
 (0)