Skip to content

Commit 2231d9c

Browse files
committed
Always call PyNumber_Index when casting from Python to a C++ integral type, also pre-3.8
1 parent 8449a80 commit 2231d9c

File tree

2 files changed

+30
-11
lines changed

2 files changed

+30
-11
lines changed

include/pybind11/cast.h

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,12 +1042,30 @@ struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_t
10421042
return false;
10431043
} else if (!convert && !index_check(src.ptr()) && !PYBIND11_LONG_CHECK(src.ptr())) {
10441044
return false;
1045-
} else if (std::is_unsigned<py_type>::value) {
1046-
py_value = as_unsigned<py_type>(src.ptr());
1047-
} else { // signed integer:
1048-
py_value = sizeof(T) <= sizeof(long)
1049-
? (py_type) PyLong_AsLong(src.ptr())
1050-
: (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr());
1045+
} else {
1046+
handle obj = src;
1047+
#if PY_VERSION_HEX < 0x03080000
1048+
bool do_decref = false;
1049+
if (PyIndex_Check(src.ptr())) {
1050+
PyObject *tmp = PyNumber_Index(src.ptr());
1051+
if (!tmp) {
1052+
py_value = (py_type) -1;
1053+
}
1054+
do_decref = true;
1055+
obj = tmp;
1056+
}
1057+
#endif
1058+
if (std::is_unsigned<py_type>::value) {
1059+
py_value = as_unsigned<py_type>(obj.ptr());
1060+
} else { // signed integer:
1061+
py_value = sizeof(T) <= sizeof(long)
1062+
? (py_type) PyLong_AsLong(obj.ptr())
1063+
: (py_type) PYBIND11_LONG_AS_LONGLONG(obj.ptr());
1064+
}
1065+
#if PY_VERSION_HEX < 0x03080000
1066+
if (do_decref)
1067+
obj.dec_ref();
1068+
#endif
10511069
}
10521070

10531071
// Python API reported an error

tests/test_builtin_casters.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,11 +289,12 @@ def cant_convert(v):
289289
require_implicit(DeepThought())
290290
cant_convert(ShallowThought())
291291
cant_convert(FuzzyThought())
292-
if env.PY >= (3, 8):
293-
# Before Python 3.8, `int(obj)` does not pick up on `obj.__index__`
294-
assert convert(IndexedThought()) == 42
295-
assert noconvert(IndexedThought()) == 42
296-
cant_convert(RaisingThought()) # no fall-back to `__int__`if `__index__` raises
292+
293+
# Before Python 3.8, `int(obj)` does not pick up on `obj.__index__`, but pybind11
294+
# "backports" this behavior.
295+
assert convert(IndexedThought()) == 42
296+
assert noconvert(IndexedThought()) == 42
297+
cant_convert(RaisingThought()) # no fall-back to `__int__`if `__index__` raises
297298

298299

299300
def test_numpy_int_convert():

0 commit comments

Comments
 (0)