Skip to content

feat(numpy): add NPY_HALF_ to npy_api::constants - #6151

Open
advitrocks9 wants to merge 2 commits into
pybind:masterfrom
advitrocks9:npy-half-typenum
Open

feat(numpy): add NPY_HALF_ to npy_api::constants#6151
advitrocks9 wants to merge 2 commits into
pybind:masterfrom
advitrocks9:npy-half-typenum

Conversation

@advitrocks9

Copy link
Copy Markdown
Contributor

Description

Fixes #4061.

npy_api::constants mirrors NumPy's NPY_TYPES, but stops at NPY_VOID_ (20) and goes straight into the platform-dependent aliases, so NPY_HALF_ (23) isn't there:

handle ptr = npy_api::get().PyArray_DescrFromType_(npy_api::NPY_HALF_);
// error: no member named 'NPY_HALF_' in 'pybind11::detail::npy_api'; did you mean 'NPY_CHAR_'?

Taking that suggestion is worse than the error. NPY_CHAR_ isn't NumPy's NPY_CHAR, it's pybind11's own is_signed<char> ? NPY_BYTE_ : NPY_UBYTE_, so it compiles cleanly and truncates float16 to int8.

py::dtype("half") already works at runtime. What's missing is the compile-time constant, which is what npy_format_descriptor<T>::value needs to specialize a user-defined half type. The workaround in #1776 reads the typenum out of NumPy's own headers, which is the dependency this header exists to avoid.

= 23 is explicit since 21 and 22 aren't mirrored. numpy.h asks for normalized_dtype_num to be reviewed alongside this enum: it's sized [NPY_VOID_ + 1] and bounds-checked before indexing, so 23 falls through unchanged, same as a float16 array does today.

No caster or format_descriptor for a concrete half type here. Which C++ type that should be is #4627.

Test specializes npy_format_descriptor for a 2-byte POD and round-trips it as numpy.float16; without the enumerator the test module doesn't compile. Suite passes on macOS arm64 with PYBIND11_WERROR=ON. No Linux or Windows box to hand, so those are down to CI.

Suggested changelog entry:

  • Added NumPy's float16 typenum to py::detail::npy_api::constants as NPY_HALF_, so a user-defined half type can specialize npy_format_descriptor without hardcoding the value.

@advitrocks9
advitrocks9 marked this pull request as ready for review August 23, 2026 21:15
Comment thread include/pybind11/numpy.h

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds the missing compile-time NumPy typenum constant for float16 to pybind11’s internal npy_api::constants, enabling users to specialize npy_format_descriptor<T> for custom half types without including NumPy headers or hardcoding values elsewhere. This aligns npy_api::constants more closely with NumPy’s NPY_TYPES and addresses the reported gap for NPY_HALF (issue #4061).

Changes:

  • Add NPY_HALF_ = 23 to pybind11::detail::npy_api::constants in include/pybind11/numpy.h.
  • Add a C++ test specialization of npy_format_descriptor for a 2-byte POD UserHalf that maps to numpy.float16.
  • Add a Python test that verifies the typenum matches NumPy’s float16 and that array_t<UserHalf> round-trips as float16.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
include/pybind11/numpy.h Exposes NPY_HALF_ (float16 typenum) in npy_api::constants for compile-time use in dtype specializations.
tests/test_numpy_dtypes.cpp Adds UserHalf + npy_format_descriptor specialization and binds helpers to validate float16 typenum and round-trip.
tests/test_numpy_dtypes.py Adds pytest coverage ensuring the new constant matches np.dtype("float16").num and round-trips with float16 dtype.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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]: NPY_HALF is not supported

3 participants