Skip to content

Commit 5f4b229

Browse files
bpo-40792: Make the result of PyNumber_Index() always having exact type int. (GH-20443)
Previously, the result could have been an instance of a subclass of int. Also revert bpo-26202 and make attributes start, stop and step of the range object having exact type int. Add private function _PyNumber_Index() which preserves the old behavior of PyNumber_Index() for performance to use it in the conversion functions like PyLong_AsLong().
1 parent eaca2aa commit 5f4b229

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+187
-187
lines changed

Doc/c-api/number.rst

+4
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,10 @@ Number Protocol
256256
Returns the *o* converted to a Python int on success or ``NULL`` with a
257257
:exc:`TypeError` exception raised on failure.
258258
259+
.. versionchanged:: 3.10
260+
The result always has exact type :class:`int`. Previously, the result
261+
could have been an instance of a subclass of ``int``.
262+
259263
260264
.. c:function:: PyObject* PyNumber_ToBase(PyObject *n, int base)
261265

Doc/library/operator.rst

+4
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ The mathematical and bitwise operations are the most numerous:
112112

113113
Return *a* converted to an integer. Equivalent to ``a.__index__()``.
114114

115+
.. versionchanged:: 3.10
116+
The result always has exact type :class:`int`. Previously, the result
117+
could have been an instance of a subclass of ``int``.
118+
115119

116120
.. function:: inv(obj)
117121
invert(obj)

Doc/whatsnew/3.10.rst

+4
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ C API Changes
129129
New Features
130130
------------
131131

132+
The result of :c:func:`PyNumber_Index` now always has exact type :class:`int`.
133+
Previously, the result could have been an instance of a subclass of ``int``.
134+
(Contributed by Serhiy Storchaka in :issue:`40792`.)
135+
132136

133137
Porting to Python 3.10
134138
----------------------

Include/cpython/abstract.h

+3
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,9 @@ PyAPI_FUNC(void) _Py_add_one_to_index_C(int nd, Py_ssize_t *index,
379379
/* Convert Python int to Py_ssize_t. Do nothing if the argument is None. */
380380
PyAPI_FUNC(int) _Py_convert_optional_to_ssize_t(PyObject *, void *);
381381

382+
/* Same as PyNumber_Index but can return an instance of a subclass of int. */
383+
PyAPI_FUNC(PyObject *) _PyNumber_Index(PyObject *o);
384+
382385
#ifdef __cplusplus
383386
}
384387
#endif

Lib/copy.py

+1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ def _deepcopy_atomic(x, memo):
192192
d[str] = _deepcopy_atomic
193193
d[types.CodeType] = _deepcopy_atomic
194194
d[type] = _deepcopy_atomic
195+
d[range] = _deepcopy_atomic
195196
d[types.BuiltinFunctionType] = _deepcopy_atomic
196197
d[types.FunctionType] = _deepcopy_atomic
197198
d[weakref.ref] = _deepcopy_atomic

Lib/test/clinic.test

+3-3
Original file line numberDiff line numberDiff line change
@@ -1332,7 +1332,7 @@ test_Py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t na
13321332
}
13331333
{
13341334
Py_ssize_t ival = -1;
1335-
PyObject *iobj = PyNumber_Index(args[0]);
1335+
PyObject *iobj = _PyNumber_Index(args[0]);
13361336
if (iobj != NULL) {
13371337
ival = PyLong_AsSsize_t(iobj);
13381338
Py_DECREF(iobj);
@@ -1347,7 +1347,7 @@ test_Py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t na
13471347
}
13481348
{
13491349
Py_ssize_t ival = -1;
1350-
PyObject *iobj = PyNumber_Index(args[1]);
1350+
PyObject *iobj = _PyNumber_Index(args[1]);
13511351
if (iobj != NULL) {
13521352
ival = PyLong_AsSsize_t(iobj);
13531353
Py_DECREF(iobj);
@@ -1373,7 +1373,7 @@ exit:
13731373
static PyObject *
13741374
test_Py_ssize_t_converter_impl(PyObject *module, Py_ssize_t a, Py_ssize_t b,
13751375
Py_ssize_t c)
1376-
/*[clinic end generated code: output=ea781bb7169b3436 input=3855f184bb3f299d]*/
1376+
/*[clinic end generated code: output=3bf73f9fdfeab468 input=3855f184bb3f299d]*/
13771377

13781378

13791379
/*[clinic input]

Lib/test/test_copy.py

+1-12
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ def f():
357357
pass
358358
tests = [None, 42, 2**100, 3.14, True, False, 1j,
359359
"hello", "hello\u1234", f.__code__,
360-
NewStyle, Classic, max, property()]
360+
NewStyle, range(10), Classic, max, property()]
361361
for x in tests:
362362
self.assertIs(copy.deepcopy(x), x)
363363

@@ -579,17 +579,6 @@ class C:
579579
self.assertIsNot(y, x)
580580
self.assertIs(y.foo, y)
581581

582-
def test_deepcopy_range(self):
583-
class I(int):
584-
pass
585-
x = range(I(10))
586-
y = copy.deepcopy(x)
587-
self.assertIsNot(y, x)
588-
self.assertEqual(y, x)
589-
self.assertIsNot(y.stop, x.stop)
590-
self.assertEqual(y.stop, x.stop)
591-
self.assertIsInstance(y.stop, I)
592-
593582
# _reconstruct()
594583

595584
def test_reconstruct_string(self):

Lib/test/test_range.py

+6
Original file line numberDiff line numberDiff line change
@@ -648,11 +648,17 @@ def test_attributes(self):
648648
self.assert_attrs(range(0, 10, 3), 0, 10, 3)
649649
self.assert_attrs(range(10, 0, -1), 10, 0, -1)
650650
self.assert_attrs(range(10, 0, -3), 10, 0, -3)
651+
self.assert_attrs(range(True), 0, 1, 1)
652+
self.assert_attrs(range(False, True), 0, 1, 1)
653+
self.assert_attrs(range(False, True, True), 0, 1, 1)
651654

652655
def assert_attrs(self, rangeobj, start, stop, step):
653656
self.assertEqual(rangeobj.start, start)
654657
self.assertEqual(rangeobj.stop, stop)
655658
self.assertEqual(rangeobj.step, step)
659+
self.assertIs(type(rangeobj.start), int)
660+
self.assertIs(type(rangeobj.stop), int)
661+
self.assertIs(type(rangeobj.step), int)
656662

657663
with self.assertRaises(AttributeError):
658664
rangeobj.start = 0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The result of :c:func:`PyNumber_Index` now always has exact type :class:`int`.
2+
Previously, the result could have been an instance of a subclass of ``int``.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Attributes ``start``, ``stop`` and ``step`` of the :class:`range` object now
2+
always has exact type :class:`int`. Previously, they could have been an
3+
instance of a subclass of ``int``.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The result of :func:`operator.index` now always has exact type :class:`int`.
2+
Previously, the result could have been an instance of a subclass of ``int``.

Modules/_io/_iomodule.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ PyNumber_AsOff_t(PyObject *item, PyObject *err)
532532
{
533533
Py_off_t result;
534534
PyObject *runerr;
535-
PyObject *value = PyNumber_Index(item);
535+
PyObject *value = _PyNumber_Index(item);
536536
if (value == NULL)
537537
return -1;
538538

Modules/_io/clinic/bufferedio.c.h

+7-7
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ _io__Buffered_peek(buffered *self, PyObject *const *args, Py_ssize_t nargs)
122122
}
123123
{
124124
Py_ssize_t ival = -1;
125-
PyObject *iobj = PyNumber_Index(args[0]);
125+
PyObject *iobj = _PyNumber_Index(args[0]);
126126
if (iobj != NULL) {
127127
ival = PyLong_AsSsize_t(iobj);
128128
Py_DECREF(iobj);
@@ -197,7 +197,7 @@ _io__Buffered_read1(buffered *self, PyObject *const *args, Py_ssize_t nargs)
197197
}
198198
{
199199
Py_ssize_t ival = -1;
200-
PyObject *iobj = PyNumber_Index(args[0]);
200+
PyObject *iobj = _PyNumber_Index(args[0]);
201201
if (iobj != NULL) {
202202
ival = PyLong_AsSsize_t(iobj);
203203
Py_DECREF(iobj);
@@ -421,7 +421,7 @@ _io_BufferedReader___init__(PyObject *self, PyObject *args, PyObject *kwargs)
421421
}
422422
{
423423
Py_ssize_t ival = -1;
424-
PyObject *iobj = PyNumber_Index(fastargs[1]);
424+
PyObject *iobj = _PyNumber_Index(fastargs[1]);
425425
if (iobj != NULL) {
426426
ival = PyLong_AsSsize_t(iobj);
427427
Py_DECREF(iobj);
@@ -475,7 +475,7 @@ _io_BufferedWriter___init__(PyObject *self, PyObject *args, PyObject *kwargs)
475475
}
476476
{
477477
Py_ssize_t ival = -1;
478-
PyObject *iobj = PyNumber_Index(fastargs[1]);
478+
PyObject *iobj = _PyNumber_Index(fastargs[1]);
479479
if (iobj != NULL) {
480480
ival = PyLong_AsSsize_t(iobj);
481481
Py_DECREF(iobj);
@@ -567,7 +567,7 @@ _io_BufferedRWPair___init__(PyObject *self, PyObject *args, PyObject *kwargs)
567567
}
568568
{
569569
Py_ssize_t ival = -1;
570-
PyObject *iobj = PyNumber_Index(PyTuple_GET_ITEM(args, 2));
570+
PyObject *iobj = _PyNumber_Index(PyTuple_GET_ITEM(args, 2));
571571
if (iobj != NULL) {
572572
ival = PyLong_AsSsize_t(iobj);
573573
Py_DECREF(iobj);
@@ -621,7 +621,7 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs)
621621
}
622622
{
623623
Py_ssize_t ival = -1;
624-
PyObject *iobj = PyNumber_Index(fastargs[1]);
624+
PyObject *iobj = _PyNumber_Index(fastargs[1]);
625625
if (iobj != NULL) {
626626
ival = PyLong_AsSsize_t(iobj);
627627
Py_DECREF(iobj);
@@ -637,4 +637,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs)
637637
exit:
638638
return return_value;
639639
}
640-
/*[clinic end generated code: output=1882bb497ddc9375 input=a9049054013a1b77]*/
640+
/*[clinic end generated code: output=98ccf7610c0e82ba input=a9049054013a1b77]*/

Modules/_io/clinic/bytesio.c.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ _io_BytesIO_seek(bytesio *self, PyObject *const *args, Py_ssize_t nargs)
404404
}
405405
{
406406
Py_ssize_t ival = -1;
407-
PyObject *iobj = PyNumber_Index(args[0]);
407+
PyObject *iobj = _PyNumber_Index(args[0]);
408408
if (iobj != NULL) {
409409
ival = PyLong_AsSsize_t(iobj);
410410
Py_DECREF(iobj);
@@ -505,4 +505,4 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs)
505505
exit:
506506
return return_value;
507507
}
508-
/*[clinic end generated code: output=ba0f302f16397741 input=a9049054013a1b77]*/
508+
/*[clinic end generated code: output=49a32140eb8c5555 input=a9049054013a1b77]*/

Modules/_io/clinic/iobase.c.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ _io__RawIOBase_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
276276
}
277277
{
278278
Py_ssize_t ival = -1;
279-
PyObject *iobj = PyNumber_Index(args[0]);
279+
PyObject *iobj = _PyNumber_Index(args[0]);
280280
if (iobj != NULL) {
281281
ival = PyLong_AsSsize_t(iobj);
282282
Py_DECREF(iobj);
@@ -310,4 +310,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored))
310310
{
311311
return _io__RawIOBase_readall_impl(self);
312312
}
313-
/*[clinic end generated code: output=1f9ce590549593be input=a9049054013a1b77]*/
313+
/*[clinic end generated code: output=83c1361a7a51ca84 input=a9049054013a1b77]*/

Modules/_io/clinic/stringio.c.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ _io_StringIO_seek(stringio *self, PyObject *const *args, Py_ssize_t nargs)
179179
}
180180
{
181181
Py_ssize_t ival = -1;
182-
PyObject *iobj = PyNumber_Index(args[0]);
182+
PyObject *iobj = _PyNumber_Index(args[0]);
183183
if (iobj != NULL) {
184184
ival = PyLong_AsSsize_t(iobj);
185185
Py_DECREF(iobj);
@@ -338,4 +338,4 @@ _io_StringIO_seekable(stringio *self, PyObject *Py_UNUSED(ignored))
338338
{
339339
return _io_StringIO_seekable_impl(self);
340340
}
341-
/*[clinic end generated code: output=9c428b2942d54991 input=a9049054013a1b77]*/
341+
/*[clinic end generated code: output=eea93dcab10d0a97 input=a9049054013a1b77]*/

Modules/_io/clinic/textio.c.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ _io_TextIOWrapper_readline(textio *self, PyObject *const *args, Py_ssize_t nargs
452452
}
453453
{
454454
Py_ssize_t ival = -1;
455-
PyObject *iobj = PyNumber_Index(args[0]);
455+
PyObject *iobj = _PyNumber_Index(args[0]);
456456
if (iobj != NULL) {
457457
ival = PyLong_AsSsize_t(iobj);
458458
Py_DECREF(iobj);
@@ -671,4 +671,4 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored))
671671
{
672672
return _io_TextIOWrapper_close_impl(self);
673673
}
674-
/*[clinic end generated code: output=ea96ee1eb3a71f77 input=a9049054013a1b77]*/
674+
/*[clinic end generated code: output=2604c8f3a45b9a03 input=a9049054013a1b77]*/

Modules/_struct.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ get_pylong(PyObject *v)
121121
if (!PyLong_Check(v)) {
122122
/* Not an integer; try to use __index__ to convert. */
123123
if (PyIndex_Check(v)) {
124-
v = PyNumber_Index(v);
124+
v = _PyNumber_Index(v);
125125
if (v == NULL)
126126
return NULL;
127127
}

Modules/arraymodule.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
344344
int do_decref = 0; /* if nb_int was called */
345345

346346
if (!PyLong_Check(v)) {
347-
v = PyNumber_Index(v);
347+
v = _PyNumber_Index(v);
348348
if (NULL == v) {
349349
return -1;
350350
}
@@ -404,7 +404,7 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
404404
int do_decref = 0; /* if nb_int was called */
405405

406406
if (!PyLong_Check(v)) {
407-
v = PyNumber_Index(v);
407+
v = _PyNumber_Index(v);
408408
if (NULL == v) {
409409
return -1;
410410
}
@@ -457,7 +457,7 @@ QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
457457
int do_decref = 0; /* if nb_int was called */
458458

459459
if (!PyLong_Check(v)) {
460-
v = PyNumber_Index(v);
460+
v = _PyNumber_Index(v);
461461
if (NULL == v) {
462462
return -1;
463463
}

Modules/clinic/_bisectmodule.c.h

+5-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/clinic/_bz2module.c.h

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/clinic/_collectionsmodule.c.h

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/clinic/_elementtree.c.h

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)