diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e23b390..cb8d40f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * Raised the minimum NumPy version to 2.0 at build time and at runtime in `pyproject.toml` and the conda recipe. `mkl_umath` built against NumPy 2 kept NumPy 2 behavior when run with NumPy 1.x, which the previous `numpy >=1.26.4` requirement allowed: complex `sign` returned NumPy 2 results and, on Windows, `patch_numpy_umath()` could not find NumPy loops matching the `int64` `ldexp` loops [gh-289](https://github.com/IntelPython/mkl_umath/pull/289) +### Fixed +* Fixed the ufunc docstrings, which held only the name of the C macro meant to supply them (e.g. `DOC_NUMPY__CORE_UMATH_SIN`): the docstring header is now generated by the build and included in the generated ufunc code [gh-282](https://github.com/IntelPython/mkl_umath/pull/282) + ### Removed * Removed the NumPy 1 code paths: the `USE_NUMPY_2` switch with the NumPy 1 complex `sign` and `ldexp_long` loops, and `ufunc_docstrings_numpy1.py`. Building against NumPy 1 headers now fails with an explicit error [gh-289](https://github.com/IntelPython/mkl_umath/pull/289) diff --git a/meson.build b/meson.build index b162475d..c9312856 100644 --- a/meson.build +++ b/meson.build @@ -141,6 +141,14 @@ gen_umath_c = custom_target( command: [py, '@INPUT@', '-o', '@OUTPUT@'] ) +gen_umath_doc_h = custom_target( + '_umath_doc_generated', + output: '_umath_doc_generated.h', + input: 'mkl_umath/generate_umath_doc.py', + command: [py, '@INPUT@', '-o', '@OUTPUT@'], + depend_files: ['mkl_umath/ufunc_docstrings_numpy2.py'] +) + gen_loops_h = custom_target( 'mkl_umath_loops_h', output: ['mkl_umath_loops.h'], @@ -189,7 +197,10 @@ loops_dep = declare_dependency(link_with: mkl_umath_loops) py.extension_module( '_ufuncs', - sources: ['mkl_umath/src/ufuncsmodule.c', gen_umath_c, gen_loops_h], + sources: [ + 'mkl_umath/src/ufuncsmodule.c', gen_umath_c, gen_umath_doc_h, + gen_loops_h + ], include_directories: inc_np, dependencies: [mkl_dep, loops_dep], c_args: c_args + ['-DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION'], diff --git a/mkl_umath/generate_umath.py b/mkl_umath/generate_umath.py index 25316e60..5f839344 100644 --- a/mkl_umath/generate_umath.py +++ b/mkl_umath/generate_umath.py @@ -29,8 +29,7 @@ # 1) The `defdict` dictionary is completely different. # 2) In the `make_arrays` function, `cfunc_fname = f"{tname}_*"` is changed to # `cfunc_fname = f"mkl_umath_{tname}_*"` -# 3) In the `make_ufuncs` function, line 988: `{doc}` is changed to `"{doc}"` -# 4) In the `make_code` function, the string used there is different. +# 3) In the `make_code` function, the string used there is different. """ Generate the code to build all the internal ufuncs. At the base is the defdict: @@ -1151,7 +1150,7 @@ def make_ufuncs(funcdict): f = PyUFunc_FromFuncAndDataAndSignatureAndIdentity( {funcs}, {data}, {signatures}, {nloops}, {nin}, {nout}, {identity}, "{name}", - "{doc}", 0, {sig}, identity + {doc}, 0, {sig}, identity ); if ({has_identity}) {{ Py_DECREF(identity); @@ -1244,6 +1243,7 @@ def make_code(funcdict, filename): #include "numpy/arrayobject.h" #include "numpy/ufuncobject.h" #include "mkl_umath_loops.h" + #include "_umath_doc_generated.h" %s static int diff --git a/mkl_umath/tests/test_basic.py b/mkl_umath/tests/test_basic.py index 8433428c..9e1bdee7 100644 --- a/mkl_umath/tests/test_basic.py +++ b/mkl_umath/tests/test_basic.py @@ -202,3 +202,11 @@ def test_absolute_nan_signbit(size, dtype): f"absolute({sign}nan) must be +nan for " f"{dtype.__name__} at size {size}" ) + + +@pytest.mark.parametrize("func", umaths) +def test_docstring(func): + # the ufunc must carry the docstring text, not the name of its C macro + doc = getattr(mu, func).__doc__ + assert "DOC_" not in doc, f"'{func}' docstring is an unexpanded macro" + assert "Parameters" in doc, f"'{func}' docstring is missing its body"