Skip to content

Commit 6e255f7

Browse files
Merge branch 'master' into type-make_tuple-fix--args/--kwargs-return-type
2 parents 00d9f81 + 8ecf10e commit 6e255f7

26 files changed

+272
-109
lines changed

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ repos:
3232

3333
# Ruff, the Python auto-correcting linter/formatter written in Rust
3434
- repo: https://github.com/astral-sh/ruff-pre-commit
35-
rev: v0.13.3
35+
rev: v0.14.3
3636
hooks:
3737
- id: ruff-check
3838
args: ["--fix", "--show-fixes"]
@@ -135,14 +135,14 @@ repos:
135135

136136
# PyLint has native support - not always usable, but works for us
137137
- repo: https://github.com/PyCQA/pylint
138-
rev: "v3.3.9"
138+
rev: "v4.0.2"
139139
hooks:
140140
- id: pylint
141141
files: ^pybind11
142142

143143
# Check schemas on some of our YAML files
144144
- repo: https://github.com/python-jsonschema/check-jsonschema
145-
rev: 0.34.0
145+
rev: 0.34.1
146146
hooks:
147147
- id: check-readthedocs
148148
- id: check-github-workflows

docs/upgrade.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ C++ enumerations as native Python types — typically standard-library
4848
``enum.Enum`` or related subclasses. This provides improved integration with
4949
Python's enum system, compared to the older (now deprecated) ``py::enum_``.
5050
See `#5555 <https://github.com/pybind/pybind11/pull/5555>`_ for details.
51+
Note that ``#include <pybind11/native_enum.h>`` is not included automatically
52+
and must be added explicitly.
5153

5254
Functions exposed with pybind11 are now pickleable. This removes a
5355
long-standing obstacle when using pybind11-bound functions with Python features

include/pybind11/cast.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,9 +347,12 @@ struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_t
347347
return PyLong_FromUnsignedLongLong((unsigned long long) src);
348348
}
349349

350-
PYBIND11_TYPE_CASTER(T,
351-
io_name<std::is_integral<T>::value>(
352-
"typing.SupportsInt", "int", "typing.SupportsFloat", "float"));
350+
PYBIND11_TYPE_CASTER(
351+
T,
352+
io_name<std::is_integral<T>::value>("typing.SupportsInt | typing.SupportsIndex",
353+
"int",
354+
"typing.SupportsFloat | typing.SupportsIndex",
355+
"float"));
353356
};
354357

355358
template <typename T>

include/pybind11/complex.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,23 @@ class type_caster<std::complex<T>> {
5454
if (!convert && !PyComplex_Check(src.ptr())) {
5555
return false;
5656
}
57-
Py_complex result = PyComplex_AsCComplex(src.ptr());
57+
handle src_or_index = src;
58+
// PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls.
59+
// The same logic is used in numeric_caster for ints and floats
60+
#if defined(PYPY_VERSION)
61+
object index;
62+
if (PYBIND11_INDEX_CHECK(src.ptr())) {
63+
index = reinterpret_steal<object>(PyNumber_Index(src.ptr()));
64+
if (!index) {
65+
PyErr_Clear();
66+
if (!convert)
67+
return false;
68+
} else {
69+
src_or_index = index;
70+
}
71+
}
72+
#endif
73+
Py_complex result = PyComplex_AsCComplex(src_or_index.ptr());
5874
if (result.real == -1.0 && PyErr_Occurred()) {
5975
PyErr_Clear();
6076
return false;
@@ -68,7 +84,10 @@ class type_caster<std::complex<T>> {
6884
return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
6985
}
7086

71-
PYBIND11_TYPE_CASTER(std::complex<T>, const_name("complex"));
87+
PYBIND11_TYPE_CASTER(
88+
std::complex<T>,
89+
io_name("typing.SupportsComplex | typing.SupportsFloat | typing.SupportsIndex",
90+
"complex"));
7291
};
7392
PYBIND11_NAMESPACE_END(detail)
7493
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

include/pybind11/detail/common.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@
103103
# define PYBIND11_DTOR_CONSTEXPR
104104
#endif
105105

106+
#if defined(PYBIND11_CPP20) && defined(__has_include) && __has_include(<barrier>)
107+
# define PYBIND11_HAS_STD_BARRIER 1
108+
#endif
109+
106110
// Compiler version assertions
107111
#if defined(__INTEL_COMPILER)
108112
# if __INTEL_COMPILER < 1800
@@ -322,6 +326,13 @@
322326
#define PYBIND11_BYTES_AS_STRING PyBytes_AsString
323327
#define PYBIND11_BYTES_SIZE PyBytes_Size
324328
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
329+
// In PyPy 7.3.3, `PyIndex_Check` is implemented by calling `__index__`,
330+
// while CPython only considers the existence of `nb_index`/`__index__`.
331+
#if !defined(PYPY_VERSION)
332+
# define PYBIND11_INDEX_CHECK(o) PyIndex_Check(o)
333+
#else
334+
# define PYBIND11_INDEX_CHECK(o) hasattr(o, "__index__")
335+
#endif
325336
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
326337
#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) (o))
327338
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) (o))

include/pybind11/gil.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,11 @@ class gil_scoped_acquire {
120120
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
121121
}
122122
# endif
123+
// Make sure that PyThreadState_Clear is not recursively called by finalizers.
124+
// See issue #5827
125+
++tstate->gilstate_counter;
123126
PyThreadState_Clear(tstate);
127+
--tstate->gilstate_counter;
124128
if (active) {
125129
PyThreadState_DeleteCurrent();
126130
}

tests/env.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import sys
55
import sysconfig
66

7-
import pytest
8-
97
ANDROID = sys.platform.startswith("android")
108
LINUX = sys.platform.startswith("linux")
119
MACOS = sys.platform.startswith("darwin")
@@ -29,19 +27,3 @@
2927
or GRAALPY
3028
or (CPYTHON and PY_GIL_DISABLED and (3, 13) <= sys.version_info < (3, 14))
3129
)
32-
33-
34-
def deprecated_call():
35-
"""
36-
pytest.deprecated_call() seems broken in pytest<3.9.x; concretely, it
37-
doesn't work on CPython 3.8.0 with pytest==3.3.2 on Ubuntu 18.04 (#2922).
38-
39-
This is a narrowed reimplementation of the following PR :(
40-
https://github.com/pytest-dev/pytest/pull/4104
41-
"""
42-
# TODO: Remove this when testing requires pytest>=3.9.
43-
pieces = pytest.__version__.split(".")
44-
pytest_major_minor = (int(pieces[0]), int(pieces[1]))
45-
if pytest_major_minor < (3, 9):
46-
return pytest.warns((DeprecationWarning, PendingDeprecationWarning))
47-
return pytest.deprecated_call()

tests/pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ addopts =
99
--capture=sys
1010
# Show local info when a failure occurs
1111
--showlocals
12-
log_cli_level = info
12+
log_level = INFO
1313
filterwarnings =
1414
# make warnings into errors but ignore certain third-party extension issues
1515
error

tests/test_builtin_casters.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ TEST_SUBMODULE(builtin_casters, m) {
363363
m.def("complex_cast", [](float x) { return "{}"_s.format(x); });
364364
m.def("complex_cast",
365365
[](std::complex<float> x) { return "({}, {})"_s.format(x.real(), x.imag()); });
366+
m.def("complex_convert", [](std::complex<float> x) { return x; });
367+
m.def("complex_noconvert", [](std::complex<float> x) { return x; }, py::arg{}.noconvert());
366368

367369
// test int vs. long (Python 2)
368370
m.def("int_cast", []() { return (int) 42; });

tests/test_builtin_casters.py

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,10 @@ def __int__(self):
286286

287287
convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
288288

289-
assert doc(convert) == "int_passthrough(arg0: typing.SupportsInt) -> int"
289+
assert (
290+
doc(convert)
291+
== "int_passthrough(arg0: typing.SupportsInt | typing.SupportsIndex) -> int"
292+
)
290293
assert doc(noconvert) == "int_passthrough_noconvert(arg0: int) -> int"
291294

292295
def requires_conversion(v):
@@ -301,7 +304,7 @@ def cant_convert(v):
301304
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
302305
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
303306
if sys.version_info < (3, 10) and env.CPYTHON:
304-
with env.deprecated_call():
307+
with pytest.deprecated_call():
305308
assert convert(Int()) == 42
306309
else:
307310
assert convert(Int()) == 42
@@ -322,19 +325,39 @@ def cant_convert(v):
322325

323326

324327
def test_float_convert(doc):
328+
class Int:
329+
def __int__(self):
330+
return -5
331+
332+
class Index:
333+
def __index__(self) -> int:
334+
return -7
335+
325336
class Float:
326337
def __float__(self):
327338
return 41.45
328339

329340
convert, noconvert = m.float_passthrough, m.float_passthrough_noconvert
330-
assert doc(convert) == "float_passthrough(arg0: typing.SupportsFloat) -> float"
341+
assert (
342+
doc(convert)
343+
== "float_passthrough(arg0: typing.SupportsFloat | typing.SupportsIndex) -> float"
344+
)
331345
assert doc(noconvert) == "float_passthrough_noconvert(arg0: float) -> float"
332346

333347
def requires_conversion(v):
334348
pytest.raises(TypeError, noconvert, v)
335349

350+
def cant_convert(v):
351+
pytest.raises(TypeError, convert, v)
352+
336353
requires_conversion(Float())
354+
requires_conversion(Index())
337355
assert pytest.approx(convert(Float())) == 41.45
356+
assert pytest.approx(convert(Index())) == -7.0
357+
assert isinstance(convert(Float()), float)
358+
assert pytest.approx(convert(3)) == 3.0
359+
requires_conversion(3)
360+
cant_convert(Int())
338361

339362

340363
def test_numpy_int_convert():
@@ -354,7 +377,7 @@ def require_implicit(v):
354377
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
355378
# https://github.com/pybind/pybind11/issues/3408
356379
if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
357-
with env.deprecated_call():
380+
with pytest.deprecated_call():
358381
assert convert(np.float32(3.14159)) == 3
359382
else:
360383
assert convert(np.float32(3.14159)) == 3
@@ -381,7 +404,7 @@ def test_tuple(doc):
381404
assert (
382405
doc(m.tuple_passthrough)
383406
== """
384-
tuple_passthrough(arg0: tuple[bool, str, typing.SupportsInt]) -> tuple[int, str, bool]
407+
tuple_passthrough(arg0: tuple[bool, str, typing.SupportsInt | typing.SupportsIndex]) -> tuple[int, str, bool]
385408
386409
Return a triple in reversed order
387410
"""
@@ -458,11 +481,61 @@ def test_reference_wrapper():
458481
assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10]
459482

460483

461-
def test_complex_cast():
484+
def test_complex_cast(doc):
462485
"""std::complex casts"""
486+
487+
class Complex:
488+
def __complex__(self) -> complex:
489+
return complex(5, 4)
490+
491+
class Float:
492+
def __float__(self) -> float:
493+
return 5.0
494+
495+
class Int:
496+
def __int__(self) -> int:
497+
return 3
498+
499+
class Index:
500+
def __index__(self) -> int:
501+
return 1
502+
463503
assert m.complex_cast(1) == "1.0"
504+
assert m.complex_cast(1.0) == "1.0"
505+
assert m.complex_cast(Complex()) == "(5.0, 4.0)"
464506
assert m.complex_cast(2j) == "(0.0, 2.0)"
465507

508+
convert, noconvert = m.complex_convert, m.complex_noconvert
509+
510+
def requires_conversion(v):
511+
pytest.raises(TypeError, noconvert, v)
512+
513+
def cant_convert(v):
514+
pytest.raises(TypeError, convert, v)
515+
516+
assert (
517+
doc(convert)
518+
== "complex_convert(arg0: typing.SupportsComplex | typing.SupportsFloat | typing.SupportsIndex) -> complex"
519+
)
520+
assert doc(noconvert) == "complex_noconvert(arg0: complex) -> complex"
521+
522+
assert convert(1) == 1.0
523+
assert convert(2.0) == 2.0
524+
assert convert(1 + 5j) == 1.0 + 5.0j
525+
assert convert(Complex()) == 5.0 + 4j
526+
assert convert(Float()) == 5.0
527+
assert isinstance(convert(Float()), complex)
528+
cant_convert(Int())
529+
assert convert(Index()) == 1
530+
assert isinstance(convert(Index()), complex)
531+
532+
requires_conversion(1)
533+
requires_conversion(2.0)
534+
assert noconvert(1 + 5j) == 1.0 + 5.0j
535+
requires_conversion(Complex())
536+
requires_conversion(Float())
537+
requires_conversion(Index())
538+
466539

467540
def test_bool_caster():
468541
"""Test bool caster implicit conversions."""

0 commit comments

Comments
 (0)