Skip to content

Fix ufunc docstrings showing the C macro name - #282

Open
antonwolfy wants to merge 3 commits into
mainfrom
fix-ufunc-docstrings
Open

antonwolfy wants to merge 3 commits into
mainfrom
fix-ufunc-docstrings

Conversation

@antonwolfy

Copy link
Copy Markdown
Collaborator

Summary

Fixes the __doc__ of every mkl_umath ufunc, which ended with a literal C macro name instead of the docstring text:

>>> mkl_umath.sin.__doc__
"sin(x, /, out=None, *, where=True, casting='same_kind', order='K', dtype=None, subok=True[, signature])\n\nDOC_NUMPY__CORE_UMATH_SIN"

All 58 public ufuncs were affected, in every release since 0.3.0. NumPy's own ufuncs are not affected by patching, since patch_numpy_umath() swaps loops, not ufunc objects.

Root cause

gh-65 aligned generate_umath.py with NumPy 2.2's docstring scheme: docstrings.get() returns the name of a DOC_* C macro, defined in a _umath_doc_generated.h header produced by generate_umath_doc.py. Two pieces of that scheme were not carried over:

  • the generator kept emitting the doc argument quoted ("{doc}"), a leftover from the previous scheme where it held the docstring text itself, so the C code got the string "DOC_NUMPY__CORE_UMATH_SIN";
  • generate_umath_doc.py was ported but never invoked by the build, so the header defining the macros was neither generated nor included.

Fix

  • meson.build: add a custom_target that generates _umath_doc_generated.h (rerun when ufunc_docstrings_numpy{1,2}.py change) and add it to the _ufuncs sources.
  • generate_umath.py: emit the macro unquoted and #include "_umath_doc_generated.h" in the generated code, matching upstream NumPy. The obsolete "difference Transition from numpy.distutils to scikit-build #3" note in the file header is removed.
  • test_basic.py: add test_docstring, checking each ufunc docstring contains no DOC_ and has its Parameters section.

Every DOC_* macro referenced by the generated code is defined by the generated header, and both ufunc_docstrings_numpy1.py and ufunc_docstrings_numpy2.py use the numpy._core.umath keys the generator expects. The header splits docstrings into adjacent literals at newlines, as NumPy does, so MSVC's string literal length limit is not hit.

Testing

Linux, icx, Python 3.13, NumPy 2.5.4: full test suite passes (450 passed, 1 skipped). The new test fails for all 58 ufuncs on a build from main. Windows, clang and NumPy 1.x builds are covered by CI.

jharlow-intel
jharlow-intel previously approved these changes Oct 15, 2026

@jharlow-intel jharlow-intel left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks, this is a nice fix! Fixing it in the generator means every ufunc gets a real docstring under both NumPy 1 and 2, and the new parametrized test will keep it that way. Just one small changelog note inline.

Comment thread CHANGELOG.md Outdated
Since the NumPy 2.x alignment (gh-65), generate_umath.py emits each
docstring as a DOC_* macro name, as NumPy does, but kept it quoted and
the header defining those macros was never generated. Every ufunc
__doc__ therefore ended with the literal macro name, e.g.
DOC_NUMPY__CORE_UMATH_SIN, instead of the docstring text.

- meson.build: generate _umath_doc_generated.h with generate_umath_doc.py
  and add it to the _ufuncs sources
- generate_umath.py: emit the macro unquoted and include the header in
  the generated code, matching upstream NumPy
- test_basic.py: check every ufunc docstring is expanded
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.

2 participants