Skip to content

Conversation

@InvincibleRMC
Copy link
Contributor

@InvincibleRMC InvincibleRMC commented Oct 23, 2025

Description

Breaking change to allow Python ints into float when under strict typing. This change was also done to complex to allow floats and ints. Now that Python ints can be passed into floats it changes behavior for overload resolution. A method that takes float that is registered before a method that takes an int will now get executed when a Python int is passed in. This overload resolution also affects methods with std::complex.

This was done to better match PEP 484 numeric tower rules.

Add typing.SupportsIndex to the int/float input types to better match fall backs.
This corrects a mistake that these where supported but, the type hint was not updated.

Change complex input types to typing.SupportsComplex | typing.SupportsFloat | typing.SupportsIndex to match runtime conversion rules.

Resolves #5878
Provides a work around for #5767

Suggested changelog entry:

Expand float and complex strict mode to allow ints and ints/float. Updates type hints to match better with typing.SupportsIndex.


📚 Documentation preview 📚: https://pybind11--5879.org.readthedocs.build/


📚 Documentation preview 📚: https://pybind11--5879.org.readthedocs.build/


📚 Documentation preview 📚: https://pybind11--5879.org.readthedocs.build/


📚 Documentation preview 📚: https://pybind11--5879.org.readthedocs.build/


📚 Documentation preview 📚: https://pybind11--5879.org.readthedocs.build/


📚 Documentation preview 📚: https://pybind11--5879.org.readthedocs.build/


📚 Documentation preview 📚: https://pybind11--5879.org.readthedocs.build/


📚 Documentation preview 📚: https://pybind11--5879.org.readthedocs.build/


📚 Documentation preview 📚: https://pybind11--5879.org.readthedocs.build/

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
@gentlegiantJGC
Copy link
Contributor

I have started working on this too.
Your code change is more complex than required.
I will finish up the documentation changes and commit what I have and you can take it from there.

@gentlegiantJGC
Copy link
Contributor

gentlegiantJGC commented Oct 23, 2025

Here is my implementation and documentation changes.
I have modified the behaviour of complex as well.
https://github.com/gentlegiantJGC/pybind11/tree/fix-pep-484
master...gentlegiantJGC:pybind11:fix-pep-484

It needs tests but I am going to stop for today.
You are welcome to use my commits.

@InvincibleRMC InvincibleRMC changed the title Expand float strict to take int Expand float strict to take int and complex strict to take float/int Oct 23, 2025
@gentlegiantJGC
Copy link
Contributor

You will need to remove the constexpr check. I didn't realise it was a newer C++ feature

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
@InvincibleRMC
Copy link
Contributor Author

TODO: figure out why it doesn't work in C++11.

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
@InvincibleRMC InvincibleRMC marked this pull request as ready for review October 24, 2025 00:59
@gentlegiantJGC
Copy link
Contributor

I have just found that a python float passed to an int argument will raise a TypeError.
It will happily except anything that implements __int__ (eg a numpy float) but explicity not a python float.

This is probably something we should resolve here because it effects these tests.

m.def("func", [](int){});
>>> func.__doc__
  func(arg: typing.SupportsInt) -> None
>>> func(5.5)
  TypeError
>>> func(numpy.float32(5.5))  # This works fine

@gentlegiantJGC
Copy link
Contributor

Here is the commit that implemented that.
3f200fa

@rwgk Can I get your input on this?
The int type caster supports anything that implements __int__ with the explicit exception of the python float.

This conflicts with the typing.SupportsInt type hint.

The int type caster allows anything that implements __int__ with explicit exception of the python float. I can't see any reason for this.
This modifies the int casting behaviour to accept a float.
If the argument is marked as noconvert() it will only accept int.
@gentlegiantJGC
Copy link
Contributor

gentlegiantJGC commented Oct 24, 2025

Here is my proposed change. You will need to update the tests.
gentlegiantJGC@d42c8e8
https://github.com/gentlegiantJGC/pybind11/tree/pr-5879-jgc

Here are my unittests
test_cast.py
cast.cpp

@InvincibleRMC
Copy link
Contributor Author

I noticed something else to have address. According to the documentation all of int,float,complex support falling back on __index__ when converting so updated the type hint from typing.SupportsInt -> typing.SupportsInt | typing.SupportsIndex. complex also supports a __float__ fall back so its type is now typing.SupportsComplex | typing.SupportsFloat | typing.SupportsIndex

@InvincibleRMC InvincibleRMC changed the title Expand float strict to take int and complex strict to take float/int Expand float and complex strict mode to allow ints and ints/float. Updates type hints to match better with typing.SupportsIndex Oct 24, 2025
@rwgk
Copy link
Collaborator

rwgk commented Oct 26, 2025

Here is the commit that implemented that. 3f200fa

@rwgk Can I get your input on this? The int type caster supports anything that implements __int__ with the explicit exception of the python float.

This conflicts with the typing.SupportsInt type hint.

I need to find a block of time to look at this carefully. Might be a couple days.

Thanks for working on this!

Comment on lines +60 to +72
#if defined(PYPY_VERSION)
object index;
if (PYBIND11_INDEX_CHECK(src.ptr())) {
index = reinterpret_steal<object>(PyNumber_Index(src.ptr()));
if (!index) {
PyErr_Clear();
if (!convert)
return false;
} else {
src_or_index = index;
}
}
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why you are doing this?
Doesn't PyComplex_AsCComplex handle that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this I was getting failures on old pypy versions see https://github.com/pybind/pybind11/actions/runs/18790097220/job/53618039827.

See this issue for more info pypy/pypy#3383

So I copied the logic from the numeric caster. Ref

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I think I understand. Can you add a comment in the code explaining it?

InvincibleRMC and others added 7 commits October 26, 2025 13:52
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Type hint conflict with noconvert float

3 participants