Skip to content

Commit

Permalink
bpo-40792: Make the result of PyNumber_Index() always having exact ty…
Browse files Browse the repository at this point in the history
…pe 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().
  • Loading branch information
serhiy-storchaka authored May 28, 2020
1 parent eaca2aa commit 5f4b229
Show file tree
Hide file tree
Showing 51 changed files with 187 additions and 187 deletions.
4 changes: 4 additions & 0 deletions Doc/c-api/number.rst
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ Number Protocol
Returns the *o* converted to a Python int on success or ``NULL`` with a
:exc:`TypeError` exception raised on failure.
.. versionchanged:: 3.10
The result always has exact type :class:`int`. Previously, the result
could have been an instance of a subclass of ``int``.
.. c:function:: PyObject* PyNumber_ToBase(PyObject *n, int base)
Expand Down
4 changes: 4 additions & 0 deletions Doc/library/operator.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ The mathematical and bitwise operations are the most numerous:

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

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


.. function:: inv(obj)
invert(obj)
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ C API Changes
New Features
------------

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


Porting to Python 3.10
----------------------
Expand Down
3 changes: 3 additions & 0 deletions Include/cpython/abstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,9 @@ PyAPI_FUNC(void) _Py_add_one_to_index_C(int nd, Py_ssize_t *index,
/* Convert Python int to Py_ssize_t. Do nothing if the argument is None. */
PyAPI_FUNC(int) _Py_convert_optional_to_ssize_t(PyObject *, void *);

/* Same as PyNumber_Index but can return an instance of a subclass of int. */
PyAPI_FUNC(PyObject *) _PyNumber_Index(PyObject *o);

#ifdef __cplusplus
}
#endif
1 change: 1 addition & 0 deletions Lib/copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ def _deepcopy_atomic(x, memo):
d[str] = _deepcopy_atomic
d[types.CodeType] = _deepcopy_atomic
d[type] = _deepcopy_atomic
d[range] = _deepcopy_atomic
d[types.BuiltinFunctionType] = _deepcopy_atomic
d[types.FunctionType] = _deepcopy_atomic
d[weakref.ref] = _deepcopy_atomic
Expand Down
6 changes: 3 additions & 3 deletions Lib/test/clinic.test
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,7 @@ test_Py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t na
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(args[0]);
PyObject *iobj = _PyNumber_Index(args[0]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand All @@ -1347,7 +1347,7 @@ test_Py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t na
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(args[1]);
PyObject *iobj = _PyNumber_Index(args[1]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand All @@ -1373,7 +1373,7 @@ exit:
static PyObject *
test_Py_ssize_t_converter_impl(PyObject *module, Py_ssize_t a, Py_ssize_t b,
Py_ssize_t c)
/*[clinic end generated code: output=ea781bb7169b3436 input=3855f184bb3f299d]*/
/*[clinic end generated code: output=3bf73f9fdfeab468 input=3855f184bb3f299d]*/


/*[clinic input]
Expand Down
13 changes: 1 addition & 12 deletions Lib/test/test_copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ def f():
pass
tests = [None, 42, 2**100, 3.14, True, False, 1j,
"hello", "hello\u1234", f.__code__,
NewStyle, Classic, max, property()]
NewStyle, range(10), Classic, max, property()]
for x in tests:
self.assertIs(copy.deepcopy(x), x)

Expand Down Expand Up @@ -579,17 +579,6 @@ class C:
self.assertIsNot(y, x)
self.assertIs(y.foo, y)

def test_deepcopy_range(self):
class I(int):
pass
x = range(I(10))
y = copy.deepcopy(x)
self.assertIsNot(y, x)
self.assertEqual(y, x)
self.assertIsNot(y.stop, x.stop)
self.assertEqual(y.stop, x.stop)
self.assertIsInstance(y.stop, I)

# _reconstruct()

def test_reconstruct_string(self):
Expand Down
6 changes: 6 additions & 0 deletions Lib/test/test_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,11 +648,17 @@ def test_attributes(self):
self.assert_attrs(range(0, 10, 3), 0, 10, 3)
self.assert_attrs(range(10, 0, -1), 10, 0, -1)
self.assert_attrs(range(10, 0, -3), 10, 0, -3)
self.assert_attrs(range(True), 0, 1, 1)
self.assert_attrs(range(False, True), 0, 1, 1)
self.assert_attrs(range(False, True, True), 0, 1, 1)

def assert_attrs(self, rangeobj, start, stop, step):
self.assertEqual(rangeobj.start, start)
self.assertEqual(rangeobj.stop, stop)
self.assertEqual(rangeobj.step, step)
self.assertIs(type(rangeobj.start), int)
self.assertIs(type(rangeobj.stop), int)
self.assertIs(type(rangeobj.step), int)

with self.assertRaises(AttributeError):
rangeobj.start = 0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The result of :c:func:`PyNumber_Index` now always has exact type :class:`int`.
Previously, the result could have been an instance of a subclass of ``int``.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Attributes ``start``, ``stop`` and ``step`` of the :class:`range` object now
always has exact type :class:`int`. Previously, they could have been an
instance of a subclass of ``int``.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The result of :func:`operator.index` now always has exact type :class:`int`.
Previously, the result could have been an instance of a subclass of ``int``.
2 changes: 1 addition & 1 deletion Modules/_io/_iomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ PyNumber_AsOff_t(PyObject *item, PyObject *err)
{
Py_off_t result;
PyObject *runerr;
PyObject *value = PyNumber_Index(item);
PyObject *value = _PyNumber_Index(item);
if (value == NULL)
return -1;

Expand Down
14 changes: 7 additions & 7 deletions Modules/_io/clinic/bufferedio.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ _io__Buffered_peek(buffered *self, PyObject *const *args, Py_ssize_t nargs)
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(args[0]);
PyObject *iobj = _PyNumber_Index(args[0]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand Down Expand Up @@ -197,7 +197,7 @@ _io__Buffered_read1(buffered *self, PyObject *const *args, Py_ssize_t nargs)
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(args[0]);
PyObject *iobj = _PyNumber_Index(args[0]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand Down Expand Up @@ -421,7 +421,7 @@ _io_BufferedReader___init__(PyObject *self, PyObject *args, PyObject *kwargs)
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(fastargs[1]);
PyObject *iobj = _PyNumber_Index(fastargs[1]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand Down Expand Up @@ -475,7 +475,7 @@ _io_BufferedWriter___init__(PyObject *self, PyObject *args, PyObject *kwargs)
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(fastargs[1]);
PyObject *iobj = _PyNumber_Index(fastargs[1]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand Down Expand Up @@ -567,7 +567,7 @@ _io_BufferedRWPair___init__(PyObject *self, PyObject *args, PyObject *kwargs)
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(PyTuple_GET_ITEM(args, 2));
PyObject *iobj = _PyNumber_Index(PyTuple_GET_ITEM(args, 2));
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand Down Expand Up @@ -621,7 +621,7 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs)
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(fastargs[1]);
PyObject *iobj = _PyNumber_Index(fastargs[1]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand All @@ -637,4 +637,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs)
exit:
return return_value;
}
/*[clinic end generated code: output=1882bb497ddc9375 input=a9049054013a1b77]*/
/*[clinic end generated code: output=98ccf7610c0e82ba input=a9049054013a1b77]*/
4 changes: 2 additions & 2 deletions Modules/_io/clinic/bytesio.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ _io_BytesIO_seek(bytesio *self, PyObject *const *args, Py_ssize_t nargs)
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(args[0]);
PyObject *iobj = _PyNumber_Index(args[0]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand Down Expand Up @@ -505,4 +505,4 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs)
exit:
return return_value;
}
/*[clinic end generated code: output=ba0f302f16397741 input=a9049054013a1b77]*/
/*[clinic end generated code: output=49a32140eb8c5555 input=a9049054013a1b77]*/
4 changes: 2 additions & 2 deletions Modules/_io/clinic/iobase.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ _io__RawIOBase_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(args[0]);
PyObject *iobj = _PyNumber_Index(args[0]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand Down Expand Up @@ -310,4 +310,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored))
{
return _io__RawIOBase_readall_impl(self);
}
/*[clinic end generated code: output=1f9ce590549593be input=a9049054013a1b77]*/
/*[clinic end generated code: output=83c1361a7a51ca84 input=a9049054013a1b77]*/
4 changes: 2 additions & 2 deletions Modules/_io/clinic/stringio.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ _io_StringIO_seek(stringio *self, PyObject *const *args, Py_ssize_t nargs)
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(args[0]);
PyObject *iobj = _PyNumber_Index(args[0]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand Down Expand Up @@ -338,4 +338,4 @@ _io_StringIO_seekable(stringio *self, PyObject *Py_UNUSED(ignored))
{
return _io_StringIO_seekable_impl(self);
}
/*[clinic end generated code: output=9c428b2942d54991 input=a9049054013a1b77]*/
/*[clinic end generated code: output=eea93dcab10d0a97 input=a9049054013a1b77]*/
4 changes: 2 additions & 2 deletions Modules/_io/clinic/textio.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ _io_TextIOWrapper_readline(textio *self, PyObject *const *args, Py_ssize_t nargs
}
{
Py_ssize_t ival = -1;
PyObject *iobj = PyNumber_Index(args[0]);
PyObject *iobj = _PyNumber_Index(args[0]);
if (iobj != NULL) {
ival = PyLong_AsSsize_t(iobj);
Py_DECREF(iobj);
Expand Down Expand Up @@ -671,4 +671,4 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored))
{
return _io_TextIOWrapper_close_impl(self);
}
/*[clinic end generated code: output=ea96ee1eb3a71f77 input=a9049054013a1b77]*/
/*[clinic end generated code: output=2604c8f3a45b9a03 input=a9049054013a1b77]*/
2 changes: 1 addition & 1 deletion Modules/_struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ get_pylong(PyObject *v)
if (!PyLong_Check(v)) {
/* Not an integer; try to use __index__ to convert. */
if (PyIndex_Check(v)) {
v = PyNumber_Index(v);
v = _PyNumber_Index(v);
if (v == NULL)
return NULL;
}
Expand Down
6 changes: 3 additions & 3 deletions Modules/arraymodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
int do_decref = 0; /* if nb_int was called */

if (!PyLong_Check(v)) {
v = PyNumber_Index(v);
v = _PyNumber_Index(v);
if (NULL == v) {
return -1;
}
Expand Down Expand Up @@ -404,7 +404,7 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
int do_decref = 0; /* if nb_int was called */

if (!PyLong_Check(v)) {
v = PyNumber_Index(v);
v = _PyNumber_Index(v);
if (NULL == v) {
return -1;
}
Expand Down Expand Up @@ -457,7 +457,7 @@ QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
int do_decref = 0; /* if nb_int was called */

if (!PyLong_Check(v)) {
v = PyNumber_Index(v);
v = _PyNumber_Index(v);
if (NULL == v) {
return -1;
}
Expand Down
10 changes: 5 additions & 5 deletions Modules/clinic/_bisectmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Modules/clinic/_bz2module.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Modules/clinic/_collectionsmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Modules/clinic/_elementtree.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 5f4b229

Please sign in to comment.