Required prerequisites
What version (or hash if on master) of pybind11 are you using?
3.0.2~3.0.4
Problem description
Summary
pybind11/complex.h's type_caster<std::complex<T>> uses io_name(input, output) with two different annotation strings:
PYBIND11_TYPE_CASTER(
std::complex<T>,
io_name("typing.SupportsComplex | typing.SupportsFloat | typing.SupportsIndex",
"complex"));
The output (return type) annotation is correctly complex. The input (parameter type) annotation is typing.SupportsComplex | typing.SupportsFloat | typing.SupportsIndex -- it does not include plain complex.
This is a real gap under strict type checking: typeshed's builtin complex type only gained __complex__ in Python >= 3.11 (see python/typeshed). Under Python 3.10 (still within pybind11's declared support window and a common requires-python floor for downstream projects), complex does not satisfy typing.SupportsComplex, so a stub generated from this caster rejects a call like f(2+1j) even though the C++ binding accepts it perfectly fine at runtime (the caster's load() uses PyComplex_AsCComplex, which handles a plain Python complex directly).
Reproduction
Any pybind11-bound function taking a std::complex<double>/std::complex<float> parameter, with a stub generated via pybind11-stubgen, produces a parameter annotation that a strict type checker (mypy/pyright under Python 3.10) rejects for a plain Python complex literal:
def f(z: typing.SupportsComplex | typing.SupportsFloat | typing.SupportsIndex) -> complex: ...
f(2 + 1j) # type-checker error under Python 3.10: complex has no __complex__
Suggested fix
Prefix the input annotation with complex |, matching the output annotation's correctness:
io_name("complex | typing.SupportsComplex | typing.SupportsFloat | typing.SupportsIndex",
"complex")
Reproducible example code
#include <complex>
#include <pybind11/complex.h>
#include <pybind11/pybind11.h>
namespace py = pybind11;
std::complex<double> ident(std::complex<double> z) {
return z;
}
PYBIND11_MODULE(complex_issue, m) {
m.def("ident", &ident);
}
Is this a regression? Put the last known working version here if it is.
3.0.1
Required prerequisites
What version (or hash if on master) of pybind11 are you using?
3.0.2~3.0.4
Problem description
Summary
pybind11/complex.h'stype_caster<std::complex<T>>usesio_name(input, output)with two different annotation strings:The output (return type) annotation is correctly
complex. The input (parameter type) annotation istyping.SupportsComplex | typing.SupportsFloat | typing.SupportsIndex-- it does not include plaincomplex.This is a real gap under strict type checking: typeshed's builtin
complextype only gained__complex__in Python >= 3.11 (see python/typeshed). Under Python 3.10 (still within pybind11's declared support window and a commonrequires-pythonfloor for downstream projects),complexdoes not satisfytyping.SupportsComplex, so a stub generated from this caster rejects a call likef(2+1j)even though the C++ binding accepts it perfectly fine at runtime (the caster'sload()usesPyComplex_AsCComplex, which handles a plain Pythoncomplexdirectly).Reproduction
Any pybind11-bound function taking a
std::complex<double>/std::complex<float>parameter, with a stub generated viapybind11-stubgen, produces a parameter annotation that a strict type checker (mypy/pyright under Python 3.10) rejects for a plain Python complex literal:Suggested fix
Prefix the input annotation with
complex |, matching the output annotation's correctness:Reproducible example code
Is this a regression? Put the last known working version here if it is.
3.0.1