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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 1 addition & 12 deletions
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

Lines changed: 6 additions & 0 deletions
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
Lines changed: 2 additions & 0 deletions
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``.
Lines changed: 3 additions & 0 deletions
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``.

0 commit comments

Comments
 (0)