Skip to content

fix: accept __index__ objects for unsigned integers without conversion so enum == numpy int works - #6193

Open
quinncheong wants to merge 2 commits into
pybind:masterfrom
quinncheong:fix/unsigned-index-noconvert
Open

quinncheong wants to merge 2 commits into
pybind:masterfrom
quinncheong:fix/unsigned-index-noconvert

Conversation

@quinncheong

@quinncheong quinncheong commented Oct 5, 2026 •

Copy link
Copy Markdown

Description

Closes #6192. Related: #5895.

Since #5887, py::enum_ comparison against a scalar uses typed overloads: (Type, Scalar) and then a catch-all (Type, const object &) that returns false. For an enum with an unsigned underlying type, the integer caster rejects __index__ objects (numpy integers among them) in the no-convert pass, because PyLong_AsUnsignedLong[Long] does not call __index__. The catch-all then matches in the same pass, so member == np.int32(3) is False while np.int32(3) == member is True. Signed underlying types are unaffected because PyLong_AsLong does call __index__.

The caster already calls PyNumber_Index explicitly on PyPy for the same reason. This change runs that path on CPython too when the target type is unsigned. The new test fails on master for the uint32_t enum and passes with the fix; the int32_t enum is the control.

Testing

Built pybind11_tests by hand from tests/pybind11_tests.cpp, tests/test_enum.cpp and tests/test_builtin_casters.cpp (g++ 11.5, -std=c++17, CPython 3.11, numpy 2.4) and ran pytest test_enum.py test_builtin_casters.py: on master the new test fails for the uint32_t enum (1 failed, 37 passed); with this change all 38 pass. I have not run the full suite, prek -a, PyPy, GraalPy or MSVC locally, so I am relying on CI for those.

Suggested changelog entry:

  • Fixed enum equality against numpy integers and other __index__ objects when the enum's underlying type is unsigned (regression in 3.1.0); unsigned integer arguments now accept __index__ objects without implicit conversion, like signed ones.

This PR was prepared with an AI coding agent (Claude Code); I reproduced the bug and ran the tests listed above before posting.

Since pybind#5887 an enum with an unsigned underlying type compares unequal to
numpy integers, because the no-convert pass rejects __index__ objects for
unsigned targets and the catch-all overload returns false. Closes pybind#6192.
The no-convert early return was previously PyPy-only, so clang-tidy never
saw it; readability-braces-around-statements now flags it.
@quinncheong

Copy link
Copy Markdown
Author

Pushed 2fa7d31 for the Clang-Tidy failure (readability-braces-around-statements on the if (!convert) return false; that used to be PyPy-only and now compiles on CPython too).

The other red jobs on the first run were not test failures: 21 were cancelled with "The job was not acquired by Runner of type hosted even after multiple attempts", and one Windows job lost contact with its runner. The test jobs that did run passed, across ubuntu, macos and windows at C++11 through C++23, including the free-threaded builds.

Prepared with an AI coding agent (Claude Code), checked by me.

This branch has not been deployed

No deployments
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]: enum __eq__ returns False against numpy integers and other __index__ objects when the enum's underlying type is unsigned (regression in 3.1.0)

1 participant