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

Skip to content

Commit df3ed24

Browse files
committed
Issue19995: %o, %x, %X now only accept ints
1 parent 6d2ea21 commit df3ed24

6 files changed

Lines changed: 72 additions & 17 deletions

File tree

Doc/reference/datamodel.rst

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2080,9 +2080,17 @@ left undefined.
20802080

20812081
.. method:: object.__index__(self)
20822082

2083-
Called to implement :func:`operator.index`. Also called whenever Python needs
2084-
an integer object (such as in slicing, or in the built-in :func:`bin`,
2085-
:func:`hex` and :func:`oct` functions). Must return an integer.
2083+
Called to implement :func:`operator.index`, and whenever Python needs to
2084+
losslessly convert the numeric object to an integer object (such as in
2085+
slicing, or in the built-in :func:`bin`, :func:`hex` and :func:`oct`
2086+
functions). Presence of this method indicates that the numeric object is
2087+
an integer type. Must return an integer.
2088+
2089+
.. note::
2090+
2091+
When :meth:`__index__` is defined, :meth:`__int__` should also be defined,
2092+
and both shuld return the same value, in order to have a coherent integer
2093+
type class.
20862094

20872095

20882096
.. _context-managers:

Lib/tarfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ def itn(n, digits=8, format=DEFAULT_FORMAT):
196196
# A 0o200 byte indicates a positive number, a 0o377 byte a negative
197197
# number.
198198
if 0 <= n < 8 ** (digits - 1):
199-
s = bytes("%0*o" % (digits - 1, n), "ascii") + NUL
199+
s = bytes("%0*o" % (digits - 1, int(n)), "ascii") + NUL
200200
elif format == GNU_FORMAT and -256 ** (digits - 1) <= n < 256 ** (digits - 1):
201201
if n >= 0:
202202
s = bytearray([0o200])

Lib/test/test_format.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@ def test_format(self):
142142
testformat("%#+027.23X", big, "+0X0001234567890ABCDEF12345")
143143
# same, except no 0 flag
144144
testformat("%#+27.23X", big, " +0X001234567890ABCDEF12345")
145-
testformat("%x", float(big), "123456_______________", 6)
146145
big = 0o12345670123456701234567012345670 # 32 octal digits
147146
testformat("%o", big, "12345670123456701234567012345670")
148147
testformat("%o", -big, "-12345670123456701234567012345670")
@@ -182,7 +181,6 @@ def test_format(self):
182181
testformat("%034.33o", big, "0012345670123456701234567012345670")
183182
# base marker shouldn't change that
184183
testformat("%0#34.33o", big, "0o012345670123456701234567012345670")
185-
testformat("%o", float(big), "123456__________________________", 6)
186184
# Some small ints, in both Python int and flavors).
187185
testformat("%d", 42, "42")
188186
testformat("%d", -42, "-42")
@@ -193,7 +191,6 @@ def test_format(self):
193191
testformat("%#x", 1, "0x1")
194192
testformat("%#X", 1, "0X1")
195193
testformat("%#X", 1, "0X1")
196-
testformat("%#x", 1.0, "0x1")
197194
testformat("%#o", 1, "0o1")
198195
testformat("%#o", 1, "0o1")
199196
testformat("%#o", 0, "0o0")
@@ -210,12 +207,10 @@ def test_format(self):
210207
testformat("%x", -0x42, "-42")
211208
testformat("%x", 0x42, "42")
212209
testformat("%x", -0x42, "-42")
213-
testformat("%x", float(0x42), "42")
214210
testformat("%o", 0o42, "42")
215211
testformat("%o", -0o42, "-42")
216212
testformat("%o", 0o42, "42")
217213
testformat("%o", -0o42, "-42")
218-
testformat("%o", float(0o42), "42")
219214
testformat("%r", "\u0378", "'\\u0378'") # non printable
220215
testformat("%a", "\u0378", "'\\u0378'") # non printable
221216
testformat("%r", "\u0374", "'\u0374'") # printable

Lib/test/test_unicode.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,35 @@ def __str__(self):
11261126
self.assertEqual('%.1s' % "a\xe9\u20ac", 'a')
11271127
self.assertEqual('%.2s' % "a\xe9\u20ac", 'a\xe9')
11281128

1129+
#issue 19995
1130+
class PsuedoInt:
1131+
def __init__(self, value):
1132+
self.value = int(value)
1133+
def __int__(self):
1134+
return self.value
1135+
def __index__(self):
1136+
return self.value
1137+
class PsuedoFloat:
1138+
def __init__(self, value):
1139+
self.value = float(value)
1140+
def __int__(self):
1141+
return int(self.value)
1142+
pi = PsuedoFloat(3.1415)
1143+
letter_m = PsuedoInt(109)
1144+
self.assertEquals('%x' % 42, '2a')
1145+
self.assertEquals('%X' % 15, 'F')
1146+
self.assertEquals('%o' % 9, '11')
1147+
self.assertEquals('%c' % 109, 'm')
1148+
self.assertEquals('%x' % letter_m, '6d')
1149+
self.assertEquals('%X' % letter_m, '6D')
1150+
self.assertEquals('%o' % letter_m, '155')
1151+
self.assertEquals('%c' % letter_m, 'm')
1152+
self.assertRaises(TypeError, '%x'.__mod__, pi)
1153+
self.assertRaises(TypeError, '%x'.__mod__, 3.14)
1154+
self.assertRaises(TypeError, '%X'.__mod__, 2.11)
1155+
self.assertRaises(TypeError, '%o'.__mod__, 1.79)
1156+
self.assertRaises(TypeError, '%c'.__mod__, pi)
1157+
11291158
def test_formatting_with_enum(self):
11301159
# issue18780
11311160
import enum

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ Core and Builtins
1818
- Issue #19969: PyBytes_FromFormatV() now raises an OverflowError if "%c"
1919
argument is not in range [0; 255].
2020

21+
- Issue #19995: %c, %o, %x, and %X now raise TypeError on non-integer input;
22+
reworded docs to clarify that an integer type should define both __int__
23+
and __index__.
24+
2125
- Issue #19787: PyThread_set_key_value() now always set the value. In Python
2226
3.3, the function did nothing if the key already exists (if the current value
2327
is a non-NULL pointer).

Objects/unicodeobject.c

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13988,7 +13988,7 @@ formatlong(PyObject *val, struct unicode_format_arg_t *arg)
1398813988
return result;
1398913989
}
1399013990

13991-
/* Format an integer.
13991+
/* Format an integer or a float as an integer.
1399213992
* Return 1 if the number has been formatted into the writer,
1399313993
* 0 if the number has been formatted into *p_output
1399413994
* -1 and raise an exception on error */
@@ -14005,11 +14005,19 @@ mainformatlong(PyObject *v,
1400514005
goto wrongtype;
1400614006

1400714007
if (!PyLong_Check(v)) {
14008-
iobj = PyNumber_Long(v);
14009-
if (iobj == NULL) {
14010-
if (PyErr_ExceptionMatches(PyExc_TypeError))
14011-
goto wrongtype;
14012-
return -1;
14008+
if (type == 'o' || type == 'x' || type == 'X') {
14009+
iobj = PyNumber_Index(v);
14010+
if (iobj == NULL) {
14011+
return -1;
14012+
}
14013+
}
14014+
else {
14015+
iobj = PyNumber_Long(v);
14016+
if (iobj == NULL ) {
14017+
if (PyErr_ExceptionMatches(PyExc_TypeError))
14018+
goto wrongtype;
14019+
return -1;
14020+
}
1401314021
}
1401414022
assert(PyLong_Check(iobj));
1401514023
}
@@ -14079,8 +14087,18 @@ formatchar(PyObject *v)
1407914087
goto onError;
1408014088
}
1408114089
else {
14082-
/* Integer input truncated to a character */
14090+
PyObject *iobj;
1408314091
long x;
14092+
/* make sure number is a type of integer */
14093+
if (!PyLong_Check(v)) {
14094+
iobj = PyNumber_Index(v);
14095+
if (iobj == NULL) {
14096+
goto onError;
14097+
}
14098+
v = iobj;
14099+
Py_DECREF(iobj);
14100+
}
14101+
/* Integer input truncated to a character */
1408414102
x = PyLong_AsLong(v);
1408514103
if (x == -1 && PyErr_Occurred())
1408614104
goto onError;
@@ -14282,7 +14300,8 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx,
1428214300
/* Format one argument. Supported conversion specifiers:
1428314301
1428414302
- "s", "r", "a": any type
14285-
- "i", "d", "u", "o", "x", "X": int
14303+
- "i", "d", "u": int or float
14304+
- "o", "x", "X": int
1428614305
- "e", "E", "f", "F", "g", "G": float
1428714306
- "c": int or str (1 character)
1428814307

0 commit comments

Comments
 (0)