From 96974ca75c17fd444bcab9bdf4a4ffebf7e50a94 Mon Sep 17 00:00:00 2001 From: "Harlow, Jordan" Date: Thu, 28 May 2026 13:11:48 -0600 Subject: [PATCH 01/14] task: CLI patch methods --- CHANGELOG.md | 1 + README.md | 40 ++++++++- mkl_umath/__main__.py | 85 +++++++++++++++++++ mkl_umath/_patch_startup.py | 33 ++++++++ mkl_umath/patch.py | 143 ++++++++++++++++++++++++++++++++ mkl_umath/tests/test_cli.py | 160 ++++++++++++++++++++++++++++++++++++ mkl_umath/with_patch.py | 96 ++++++++++++++++++++++ 7 files changed, 557 insertions(+), 1 deletion(-) create mode 100644 mkl_umath/__main__.py create mode 100644 mkl_umath/_patch_startup.py create mode 100644 mkl_umath/patch.py create mode 100644 mkl_umath/tests/test_cli.py create mode 100644 mkl_umath/with_patch.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 17bcc571..26dd80db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [dev] - YYYY-MM-DD ### Added +* Added CLI patch management for NumPy umath with persistent install/status/uninstall and one-shot command patching via `python -m mkl_umath --patch ` and `python -m mkl_umath --with-numpy-patch ` ### Changed * Removed `numpy-base` dependency and `USE_NUMPY_BASE` environment variable from conda recipe [gh-200](https://github.com/IntelPython/mkl_umath/pull/200) diff --git a/README.md b/README.md index 57f260e4..2dac9769 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,45 @@ Where `` should be the latest version from https://software.repos # Patching Mechanisms -`mkl_umath` provides a convenient programmatic patch method to enable MKL-accelerated umath operations in NumPy. +`mkl_umath` provides convenient patch methods to enable MKL-accelerated +umath operations in NumPy with or without modifying your code. + +## CLI Quickstart + +### Persistent patch (all Python sessions) + +```bash +# Install +python -m mkl_umath --patch install + +# Status (exit code: 0 = installed, 1 = not installed) +python -m mkl_umath --patch status + +# Remove +python -m mkl_umath --patch uninstall +``` + +### Verify patch state + +```bash +python -c "import mkl_umath; print(f'mkl_umath.is_patched(): {mkl_umath.is_patched()}')" +``` + +### One-shot patch (single command only) + +```bash +# Script +python -m mkl_umath --with-numpy-patch my_script.py + +# Pytest +python -m mkl_umath --with-numpy-patch -m pytest tests/ + +# One-liner +python -m mkl_umath --with-numpy-patch -c "import mkl_umath; print(f\"mkl_umath.is_patched(): {mkl_umath.is_patched()}\")" + +# Non-Python command +python -m mkl_umath --with-numpy-patch -- [args...] +``` ## Programmatic Quickstart diff --git a/mkl_umath/__main__.py b/mkl_umath/__main__.py new file mode 100644 index 00000000..72af9bbb --- /dev/null +++ b/mkl_umath/__main__.py @@ -0,0 +1,85 @@ +# Copyright (c) 2026, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Command-line interface for mkl_umath.""" + +import argparse +import sys + + +def main(): + """Entry point for the CLI.""" + parser = argparse.ArgumentParser( + prog="python -m mkl_umath", + description="MKL-accelerated universal functions for NumPy", + ) + parser.add_argument( + "-v", "--verbose", action="store_true", help="Enable verbose output" + ) + parser.add_argument( + "--patch", + choices=["install", "uninstall", "status"], + help="Manage persistent NumPy umath patching", + ) + parser.add_argument( + "--with-numpy-patch", + dest="with_numpy_patch", + nargs=argparse.REMAINDER, + help="Run command with temporary NumPy umath patch", + ) + + args = parser.parse_args() + + if args.patch: + from mkl_umath.patch import ( + PatchOperationError, + check_status, + install_patch, + uninstall_patch, + ) + + try: + if args.patch == "install": + install_patch(verbose=args.verbose) + elif args.patch == "uninstall": + uninstall_patch(verbose=args.verbose) + elif args.patch == "status": + sys.exit(0 if check_status(verbose=args.verbose) else 1) + except PatchOperationError as exc: + print(exc, file=sys.stderr) + sys.exit(1) + + elif args.with_numpy_patch is not None: + from mkl_umath.with_patch import run_with_numpy_patch + + run_with_numpy_patch(args.with_numpy_patch) + + else: + parser.print_help() + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/mkl_umath/_patch_startup.py b/mkl_umath/_patch_startup.py new file mode 100644 index 00000000..b88891c5 --- /dev/null +++ b/mkl_umath/_patch_startup.py @@ -0,0 +1,33 @@ +# Copyright (c) 2026, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Helper module for .pth-based persistent patching with error handling.""" + +try: + import mkl_umath + + mkl_umath.patch_numpy_umath() +except Exception: + pass diff --git a/mkl_umath/patch.py b/mkl_umath/patch.py new file mode 100644 index 00000000..ac27eab8 --- /dev/null +++ b/mkl_umath/patch.py @@ -0,0 +1,143 @@ +# Copyright (c) 2026, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Persistent patch management for NumPy umath submodule.""" + +import site +import sys +import warnings +from pathlib import Path + + +class PatchOperationError(RuntimeError): + """Raised when a persistent patch operation cannot be completed.""" + + +def get_pth_path(): + """Get the path to mkl_umath_patch.pth in the appropriate site-packages.""" + site_packages = site.getsitepackages() + if site_packages: + target_site = site_packages[0] + else: + target_site = site.getusersitepackages() + return Path(target_site) / "mkl_umath_patch.pth" + + +PTH_CONTENT = """import mkl_umath._patch_startup""" + + +def install_patch(verbose=False): + """Install persistent NumPy umath patch using .pth file.""" + pth_path = get_pth_path() + + if pth_path.exists(): + if verbose: + warnings.warn( + f"Persistent patch already installed at {pth_path}", + UserWarning, + stacklevel=2, + ) + return + + try: + pth_path.parent.mkdir(parents=True, exist_ok=True) + pth_path.write_text(PTH_CONTENT) + if verbose: + print(f"Persistent patch installed at {pth_path}") + print() + print( + "NumPy umath will now use MKL-accelerated implementations in" + ) + print("all Python sessions. To disable, run:") + print(" python -m mkl_umath --patch uninstall") + except OSError as e: + raise PatchOperationError( + f"Error installing patch at {pth_path}: {e}\n\n" + "You may need to run with appropriate permissions or install to " + "a user site-packages directory." + ) from e + + +def uninstall_patch(verbose=False): + """Uninstall persistent NumPy umath patch.""" + pth_path = get_pth_path() + + if not pth_path.exists(): + if verbose: + print("No persistent patch found.") + return + + try: + pth_path.unlink() + if verbose: + print(f"Persistent patch removed from {pth_path}") + print() + print("NumPy umath will now use the default implementations.") + except OSError as e: + raise PatchOperationError( + f"Error removing patch at {pth_path}: {e}" + ) from e + + +def check_status(verbose=False): + """Check if persistent patch is installed.""" + pth_path = get_pth_path() + + if pth_path.exists(): + if verbose: + print(f"Persistent patch is installed at {pth_path}") + print() + print( + "NumPy umath is configured to use MKL-accelerated " + "implementations." + ) + return True + else: + if verbose: + print("No persistent patch installed") + print() + print("To enable MKL-accelerated NumPy umath globally, run:") + print(" python -m mkl_umath --patch install") + return False + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python -m mkl_umath.patch ") + sys.exit(1) + + command = sys.argv[1] + try: + if command == "install": + install_patch(verbose=True) + elif command == "uninstall": + uninstall_patch(verbose=True) + elif command == "status": + sys.exit(0 if check_status(verbose=True) else 1) + else: + print(f"Unknown command: {command}") + sys.exit(1) + except PatchOperationError as exc: + print(exc, file=sys.stderr) + sys.exit(1) diff --git a/mkl_umath/tests/test_cli.py b/mkl_umath/tests/test_cli.py new file mode 100644 index 00000000..cb77a0eb --- /dev/null +++ b/mkl_umath/tests/test_cli.py @@ -0,0 +1,160 @@ +# Copyright (c) 2026, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import site + +import pytest + +import mkl_umath +from mkl_umath.patch import ( + PatchOperationError, + check_status, + install_patch, + uninstall_patch, +) + + +@pytest.fixture +def mock_pth_path(tmp_path, monkeypatch): + """Mock the .pth file path to use a temporary directory.""" + pth_file = tmp_path / "mkl_umath_patch.pth" + + def mock_get_pth_path(): + return pth_file + + monkeypatch.setattr("mkl_umath.patch.get_pth_path", mock_get_pth_path) + return pth_file + + +def test_install_patch(mock_pth_path, capsys): + """Test installing persistent patch.""" + install_patch(verbose=True) + + assert mock_pth_path.exists() + content = mock_pth_path.read_text() + assert "import mkl_umath._patch_startup" in content + + captured = capsys.readouterr() + assert "Persistent patch installed" in captured.out + + +def test_install_patch_already_installed(mock_pth_path): + """Test installing patch when already installed.""" + install_patch() + with pytest.warns(UserWarning, match="already installed"): + install_patch(verbose=True) + + +def test_uninstall_patch(mock_pth_path, capsys): + """Test uninstalling persistent patch.""" + install_patch() + assert mock_pth_path.exists() + + uninstall_patch(verbose=True) + assert not mock_pth_path.exists() + + captured = capsys.readouterr() + assert "Persistent patch removed" in captured.out + + +def test_uninstall_patch_not_installed(mock_pth_path, capsys): + """Test uninstalling patch when not installed.""" + uninstall_patch(verbose=True) + + captured = capsys.readouterr() + assert "No persistent patch found" in captured.out + + +def test_patch_status_check_function(mock_pth_path): + """Test check_status function return values.""" + assert not check_status() + + install_patch() + assert check_status() + + uninstall_patch() + assert not check_status() + + +def test_install_patch_enables_runtime_patch_via_pth(mock_pth_path): + """Test that .pth activation results in patched NumPy umath runtime state.""" + install_patch() + + preexisting_patch_state = mkl_umath.is_patched() + try: + site.addsitedir(str(mock_pth_path.parent)) + assert mkl_umath.is_patched() + finally: + if mkl_umath.is_patched() and not preexisting_patch_state: + mkl_umath.restore_numpy_umath() + + +def test_install_patch_raises_patch_operation_error_on_oserror( + mock_pth_path, monkeypatch +): + """Test install_patch raises a typed error for filesystem failures.""" + + def mock_write_text(*args, **kwargs): + raise OSError("mock write failure") + + monkeypatch.setattr("pathlib.Path.write_text", mock_write_text) + + with pytest.raises(PatchOperationError, match="Error installing patch"): + install_patch() + + +def test_uninstall_patch_raises_patch_operation_error_on_oserror( + mock_pth_path, monkeypatch +): + """Test uninstall_patch raises a typed error for filesystem failures.""" + install_patch() + + def mock_unlink(*args, **kwargs): + raise OSError("mock unlink failure") + + monkeypatch.setattr("pathlib.Path.unlink", mock_unlink) + + with pytest.raises(PatchOperationError, match="Error removing patch"): + uninstall_patch() + + +def test_cli_patch_install_exits_with_error_on_patch_operation_error( + monkeypatch, capsys +): + """Test CLI maps patch operation failures to exit code 1.""" + from mkl_umath import __main__ as cli_main + + def mock_install_patch(*args, **kwargs): + raise PatchOperationError("mock cli install failure") + + monkeypatch.setattr("mkl_umath.patch.install_patch", mock_install_patch) + monkeypatch.setattr("sys.argv", ["python", "--patch", "install"]) + + with pytest.raises(SystemExit) as exc_info: + cli_main.main() + + assert exc_info.value.code == 1 + captured = capsys.readouterr() + assert "mock cli install failure" in captured.err diff --git a/mkl_umath/with_patch.py b/mkl_umath/with_patch.py new file mode 100644 index 00000000..f40694d6 --- /dev/null +++ b/mkl_umath/with_patch.py @@ -0,0 +1,96 @@ +# Copyright (c) 2026, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Run Python commands with temporary NumPy umath patch.""" + +import os +import subprocess +import sys +import tempfile + + +def run_with_numpy_patch(args): + """Run a command with mkl_umath NumPy patch enabled. + + Automatically prepends 'python' unless args start with '--'. + """ + if not args: + print( + "Usage: python -m mkl_umath --with-numpy-patch " + "" + ) + print() + print("Examples:") + print(" python -m mkl_umath --with-numpy-patch script.py") + print( + " python -m mkl_umath --with-numpy-patch -c 'import mkl_umath; " + "print(mkl_umath.is_patched())'" + ) + print(" python -m mkl_umath --with-numpy-patch -m pytest tests/") + print(" python -m mkl_umath --with-numpy-patch -- any command here") + sys.exit(1) + + # strip leading '--' and run as-is + if args[0] == "--": + args = args[1:] + # prepend 'python' for convenience + else: + args = [sys.executable] + args + + sitecustomize_content = """# mkl_umath temporary patch +try: + import mkl_umath + mkl_umath.patch_numpy_umath() +except Exception: + pass +""" + + temp_dir = tempfile.mkdtemp(prefix="mkl_umath_patch_") + sitecustomize_path = os.path.join(temp_dir, "sitecustomize.py") + + try: + with open(sitecustomize_path, "w") as f: + f.write(sitecustomize_content) + + env = os.environ.copy() + + existing_pythonpath = env.get("PYTHONPATH", "") + if existing_pythonpath: + env["PYTHONPATH"] = f"{temp_dir}{os.pathsep}{existing_pythonpath}" + else: + env["PYTHONPATH"] = temp_dir + + result = subprocess.run(args, env=env) + sys.exit(result.returncode) + finally: + try: + os.unlink(sitecustomize_path) + os.rmdir(temp_dir) + except OSError: + pass + + +if __name__ == "__main__": + run_with_numpy_patch(sys.argv[1:]) From 0351a4bf122be312f9ff1dbfb9ce02d065942f45 Mon Sep 17 00:00:00 2001 From: "Harlow, Jordan" Date: Thu, 28 May 2026 13:13:52 -0600 Subject: [PATCH 02/14] chore: CHANGELOG PR linking --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26dd80db..7590ad71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [dev] - YYYY-MM-DD ### Added -* Added CLI patch management for NumPy umath with persistent install/status/uninstall and one-shot command patching via `python -m mkl_umath --patch ` and `python -m mkl_umath --with-numpy-patch ` +* Added CLI patch management for NumPy umath with persistent install/status/uninstall and one-shot command patching via `python -m mkl_umath --patch ` and `python -m mkl_umath --with-numpy-patch ` [gh-216](https://github.com/IntelPython/mkl_umath/pull/216) ### Changed * Removed `numpy-base` dependency and `USE_NUMPY_BASE` environment variable from conda recipe [gh-200](https://github.com/IntelPython/mkl_umath/pull/200) From 2e5ca5565670dc893e7f41cda3d6768c92fe0996 Mon Sep 17 00:00:00 2001 From: "Harlow, Jordan" Date: Thu, 28 May 2026 13:18:35 -0600 Subject: [PATCH 03/14] chore: precommit --- mkl_umath/patch.py | 4 +--- mkl_umath/tests/test_cli.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mkl_umath/patch.py b/mkl_umath/patch.py index ac27eab8..a707e9c5 100644 --- a/mkl_umath/patch.py +++ b/mkl_umath/patch.py @@ -66,9 +66,7 @@ def install_patch(verbose=False): if verbose: print(f"Persistent patch installed at {pth_path}") print() - print( - "NumPy umath will now use MKL-accelerated implementations in" - ) + print("NumPy umath will now use MKL-accelerated implementations in") print("all Python sessions. To disable, run:") print(" python -m mkl_umath --patch uninstall") except OSError as e: diff --git a/mkl_umath/tests/test_cli.py b/mkl_umath/tests/test_cli.py index cb77a0eb..fe74a0b0 100644 --- a/mkl_umath/tests/test_cli.py +++ b/mkl_umath/tests/test_cli.py @@ -99,7 +99,7 @@ def test_patch_status_check_function(mock_pth_path): def test_install_patch_enables_runtime_patch_via_pth(mock_pth_path): - """Test that .pth activation results in patched NumPy umath runtime state.""" + """Test that .pth activation yields patched NumPy umath runtime state.""" install_patch() preexisting_patch_state = mkl_umath.is_patched() From ac204c85f98ab66cfb049f77ad9c9acf58b02bb2 Mon Sep 17 00:00:00 2001 From: vchamarthi Date: Tue, 16 Jun 2026 10:03:21 -0500 Subject: [PATCH 04/14] separate class for each ufunc --- benchmarks/benchmarks/micro/bench_micro.py | 38 ++++++++++++++-------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/benchmarks/benchmarks/micro/bench_micro.py b/benchmarks/benchmarks/micro/bench_micro.py index 5302f5bb..5b4b4ec5 100644 --- a/benchmarks/benchmarks/micro/bench_micro.py +++ b/benchmarks/benchmarks/micro/bench_micro.py @@ -1,8 +1,7 @@ """Micro-benchmarks for mkl_umath unary ufuncs. -Times each ufunc over a Cartesian product of - dtype in [float32, float64] - size in [10_000, 100_000, 1_000_000] +Each ufunc gets its own benchmark class (Bench_) so ASV renders a +separate grid tile per ufunc. Params are dtype x size only. Arrays are pre-allocated in setup() and reused across timing calls. Patching is applied once at package import via benchmarks._patch_setup. @@ -39,24 +38,35 @@ } -class BenchMicro: - params = ( - sorted(_UFUNC_CONFIGS.keys()), - ["float32", "float64"], - [10_000, 100_000, 1_000_000], - ) - param_names = ["ufunc", "dtype", "size"] - - def setup(self, ufunc, dtype, size): - cfg = _UFUNC_CONFIGS[ufunc] +def _make_bench(name, cfg): + def setup(self, dtype, size): rng = np.random.default_rng(42) self.x = rng.uniform(cfg["low"], cfg["high"], size).astype(dtype) self._func = cfg["func"] self._func(self.x) - def time_micro(self, ufunc, dtype, size): + def time_ufunc(self, dtype, size): self._func(self.x) + return type( + f"Bench_{name}", + (), + { + "params": (["float32", "float64"], [10_000, 100_000, 1_000_000]), + "param_names": ["dtype", "size"], + "setup": setup, + "time_ufunc": time_ufunc, + }, + ) + + +globals().update( + { + f"Bench_{name}": _make_bench(name, cfg) + for name, cfg in _UFUNC_CONFIGS.items() + } +) + class BenchArctan2: """Binary ufunc arctan2""" From b8865678ea08a31b37b53e8cb0fa9c75dca3345e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 23:33:10 +0000 Subject: [PATCH 05/14] Bump actions/checkout from 6.0.3 to 7.0.0 Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.3 to 7.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/df4cb1c069e1874edd31b4311f1884172cec0e10...9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-with-clang.yml | 2 +- .github/workflows/build_pip.yaml | 2 +- .github/workflows/conda-package-cf.yml | 4 ++-- .github/workflows/conda-package.yml | 4 ++-- .github/workflows/openssf-scorecard.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-with-clang.yml b/.github/workflows/build-with-clang.yml index d598ce3a..7ddaa7d9 100644 --- a/.github/workflows/build-with-clang.yml +++ b/.github/workflows/build-with-clang.yml @@ -49,7 +49,7 @@ jobs: architecture: x64 - name: Checkout repo - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 diff --git a/.github/workflows/build_pip.yaml b/.github/workflows/build_pip.yaml index 6219dc0b..4dded434 100644 --- a/.github/workflows/build_pip.yaml +++ b/.github/workflows/build_pip.yaml @@ -27,7 +27,7 @@ jobs: sudo apt-get install jq - name: Checkout repo - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 diff --git a/.github/workflows/conda-package-cf.yml b/.github/workflows/conda-package-cf.yml index 5aadada0..cbac9d25 100644 --- a/.github/workflows/conda-package-cf.yml +++ b/.github/workflows/conda-package-cf.yml @@ -37,7 +37,7 @@ jobs: uses: styfle/cancel-workflow-action@d07a454dad7609a92316b57b23c9ccfd4f59af66 # 0.13.1 with: access_token: ${{ github.token }} - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 @@ -205,7 +205,7 @@ jobs: uses: styfle/cancel-workflow-action@d07a454dad7609a92316b57b23c9ccfd4f59af66 # 0.13.1 with: access_token: ${{ github.token }} - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 diff --git a/.github/workflows/conda-package.yml b/.github/workflows/conda-package.yml index 4f22b81f..18e537c7 100644 --- a/.github/workflows/conda-package.yml +++ b/.github/workflows/conda-package.yml @@ -37,7 +37,7 @@ jobs: uses: styfle/cancel-workflow-action@d07a454dad7609a92316b57b23c9ccfd4f59af66 # 0.13.1 with: access_token: ${{ github.token }} - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 @@ -205,7 +205,7 @@ jobs: uses: styfle/cancel-workflow-action@d07a454dad7609a92316b57b23c9ccfd4f59af66 # 0.13.1 with: access_token: ${{ github.token }} - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 diff --git a/.github/workflows/openssf-scorecard.yml b/.github/workflows/openssf-scorecard.yml index a05b17d3..e4d2f6dc 100644 --- a/.github/workflows/openssf-scorecard.yml +++ b/.github/workflows/openssf-scorecard.yml @@ -36,7 +36,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index af315865..1da81158 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Checkout repo - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Set up python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v5.6.0 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 9cce09ab..8a176692 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -13,7 +13,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout repo - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # use commit hash to make "no-commit-to-branch" check passing ref: ${{ github.sha }} From 6430b2cfa9a6122dc36dd6a5e9a0fdab75993cc1 Mon Sep 17 00:00:00 2001 From: ndgrigorian <46709016+ndgrigorian@users.noreply.github.com> Date: Sat, 27 Jun 2026 03:43:29 +0000 Subject: [PATCH 06/14] chore: update pre-commit hooks --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4d1e3989..3898bd4a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -58,7 +58,7 @@ repos: args: ["-i"] - repo: https://github.com/MarcoGorelli/cython-lint - rev: v0.19.0 + rev: v0.21.0 hooks: - id: cython-lint - id: double-quote-cython-strings From 79ede33d679f7b00f5ecb34f2d0f0892a3bab892 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Tue, 9 Jun 2026 12:55:25 -0700 Subject: [PATCH 07/14] add getter for ufunc types NumPy 2.5+ changed how types property is exposed in NumPy, causing indexing on the types to break also fixes a bug where patching would attempt to free null pointers when patching process fails midway --- mkl_umath/src/_patch_numpy.pyx | 54 ++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/mkl_umath/src/_patch_numpy.pyx b/mkl_umath/src/_patch_numpy.pyx index 598a0167..27712bb4 100644 --- a/mkl_umath/src/_patch_numpy.pyx +++ b/mkl_umath/src/_patch_numpy.pyx @@ -40,6 +40,16 @@ from libc.stdlib cimport free, malloc cnp.import_umath() +cdef extern from *: + """ + #include "numpy/ufuncobject.h" + static inline char* _get_ufunc_types(PyObject *u) { + return (char *)((PyUFuncObject *)u)->types; + } + """ + char* _get_ufunc_types(object u) noexcept + + ctypedef struct function_info: cnp.PyUFuncGenericFunction original_function cnp.PyUFuncGenericFunction patch_function @@ -53,32 +63,39 @@ cdef class _patch_impl: functions_dict = dict() def __cinit__(self): - cdef int pi, oi + cdef int pi, oi, i, nargs + cdef int expected_count + cdef char* patch_types + cdef char* orig_types - umaths = [i for i in dir(mu) if isinstance(getattr(mu, i), np.ufunc)] + self.functions = NULL self.functions_count = 0 + + umaths = [x for x in dir(mu) if isinstance(getattr(mu, x), np.ufunc)] + expected_count = 0 for umath in umaths: mkl_umath_func = getattr(mu, umath) - self.functions_count += mkl_umath_func.ntypes + expected_count += mkl_umath_func.ntypes self.functions = malloc( - self.functions_count * sizeof(function_info) + expected_count * sizeof(function_info) ) - func_number = 0 for umath in umaths: patch_umath = getattr(mu, umath) c_patch_umath = patch_umath c_orig_umath = getattr(np, umath) nargs = c_patch_umath.nargs + patch_types = _get_ufunc_types(c_patch_umath) + orig_types = _get_ufunc_types(c_orig_umath) for pi in range(c_patch_umath.ntypes): oi = 0 while oi < c_orig_umath.ntypes: found = True - for i in range(c_patch_umath.nargs): + for i in range(nargs): if ( - c_patch_umath.types[pi * nargs + i] - != c_orig_umath.types[oi * nargs + i] + patch_types[pi * nargs + i] + != orig_types[oi * nargs + i] ): found = False break @@ -86,23 +103,23 @@ cdef class _patch_impl: break oi = oi + 1 if oi < c_orig_umath.ntypes: - self.functions[func_number].original_function = ( + self.functions[self.functions_count].original_function = ( c_orig_umath.functions[oi] ) - self.functions[func_number].patch_function = ( + self.functions[self.functions_count].patch_function = ( c_patch_umath.functions[pi] ) - self.functions[func_number].signature = ( + self.functions[self.functions_count].signature = ( malloc(nargs * sizeof(int)) ) for i in range(nargs): - self.functions[func_number].signature[i] = ( - c_patch_umath.types[pi * nargs + i] + self.functions[self.functions_count].signature[i] = ( + patch_types[pi * nargs + i] ) self.functions_dict[(umath, patch_umath.types[pi])] = ( - func_number + self.functions_count ) - func_number = func_number + 1 + self.functions_count += 1 else: raise RuntimeError( f"Unable to find original function for: {umath} " @@ -110,9 +127,10 @@ cdef class _patch_impl: ) def __dealloc__(self): - for i in range(self.functions_count): - free(self.functions[i].signature) - free(self.functions) + if self.functions is not NULL: + for i in range(self.functions_count): + free(self.functions[i].signature) + free(self.functions) cdef int _replace_loop( self, From df5762ea398d086f0daa799dd497c9c0a922b9a3 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Mon, 29 Jun 2026 08:27:42 -0700 Subject: [PATCH 08/14] add gh-226 to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a868bb7b..7b129cdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * Removed `numpy-base` dependency and `USE_NUMPY_BASE` environment variable from conda recipe [gh-200](https://github.com/IntelPython/mkl_umath/pull/200) +* Updated `mkl_umath` patching to work with changes to NumPy Cython API present in NumPy 2.5 [gh-226](https://github.com/IntelPython/mkl_umath/pull/226) ### Fixed From db4fe070fe11be02172cd498f641821662005631 Mon Sep 17 00:00:00 2001 From: Nikita Grigorian Date: Mon, 29 Jun 2026 08:45:11 -0700 Subject: [PATCH 09/14] apply review comments --- mkl_umath/src/_patch_numpy.pyx | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/mkl_umath/src/_patch_numpy.pyx b/mkl_umath/src/_patch_numpy.pyx index 27712bb4..4338bf2d 100644 --- a/mkl_umath/src/_patch_numpy.pyx +++ b/mkl_umath/src/_patch_numpy.pyx @@ -59,10 +59,10 @@ ctypedef struct function_info: cdef class _patch_impl: cdef int functions_count cdef function_info* functions - - functions_dict = dict() + cdef dict functions_dict def __cinit__(self): + self.functions_dict = {} cdef int pi, oi, i, nargs cdef int expected_count cdef char* patch_types @@ -77,15 +77,25 @@ cdef class _patch_impl: mkl_umath_func = getattr(mu, umath) expected_count += mkl_umath_func.ntypes - self.functions = malloc( - expected_count * sizeof(function_info) - ) + if expected_count > 0: + self.functions = malloc( + expected_count * sizeof(function_info) + ) + if self.functions is NULL: + raise MemoryError( + "Failed to allocate memory for function_info array" + ) for umath in umaths: patch_umath = getattr(mu, umath) c_patch_umath = patch_umath c_orig_umath = getattr(np, umath) + # nargs must be >=0 as no ufuncs have no arguments nargs = c_patch_umath.nargs + if nargs <= 0: + raise RuntimeError( + f"Invalid number of arguments for ufunc {umath}: {nargs}" + ) patch_types = _get_ufunc_types(c_patch_umath) orig_types = _get_ufunc_types(c_orig_umath) for pi in range(c_patch_umath.ntypes): @@ -129,7 +139,8 @@ cdef class _patch_impl: def __dealloc__(self): if self.functions is not NULL: for i in range(self.functions_count): - free(self.functions[i].signature) + if self.functions[i].signature is not NULL: + free(self.functions[i].signature) free(self.functions) cdef int _replace_loop( From 7c3ac304c6d933dc79888294811eb6919c92aa7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 23:32:55 +0000 Subject: [PATCH 10/14] Bump actions/cache from 5.0.5 to 6.1.0 Bumps [actions/cache](https://github.com/actions/cache) from 5.0.5 to 6.1.0. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/27d5ce7f107fe9357f9df03efb73ab90386fccae...55cc8345863c7cc4c66a329aec7e433d2d1c52a9) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/conda-package-cf.yml | 8 ++++---- .github/workflows/conda-package.yml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/conda-package-cf.yml b/.github/workflows/conda-package-cf.yml index 5aadada0..9eb154e4 100644 --- a/.github/workflows/conda-package-cf.yml +++ b/.github/workflows/conda-package-cf.yml @@ -46,7 +46,7 @@ jobs: echo "pkgs_dirs: [~/.conda/pkgs]" >> ~/.condarc - name: Cache conda packages - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 env: CACHE_NUMBER: 0 # Increase to reset cache with: @@ -151,7 +151,7 @@ jobs: echo "pkgs_dirs: [~/.conda/pkgs]" >> ~/.condarc - name: Cache conda packages - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 env: CACHE_NUMBER: 0 # Increase to reset cache with: @@ -219,7 +219,7 @@ jobs: conda-build-version: ${{ env.CONDA_BUILD_VERSION }} - name: Cache conda packages - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 env: CACHE_NUMBER: 3 # Increase to reset cache with: @@ -346,7 +346,7 @@ jobs: run: Get-Content -Path .\lockfile - name: Cache conda packages - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 env: CACHE_NUMBER: 0 # Increase to reset cache with: diff --git a/.github/workflows/conda-package.yml b/.github/workflows/conda-package.yml index 4f22b81f..0af1252e 100644 --- a/.github/workflows/conda-package.yml +++ b/.github/workflows/conda-package.yml @@ -46,7 +46,7 @@ jobs: echo "pkgs_dirs: [~/.conda/pkgs]" >> ~/.condarc - name: Cache conda packages - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 env: CACHE_NUMBER: 0 # Increase to reset cache with: @@ -151,7 +151,7 @@ jobs: echo "pkgs_dirs: [~/.conda/pkgs]" >> ~/.condarc - name: Cache conda packages - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 env: CACHE_NUMBER: 0 # Increase to reset cache with: @@ -219,7 +219,7 @@ jobs: conda-build-version: ${{ env.CONDA_BUILD_VERSION }} - name: Cache conda packages - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 env: CACHE_NUMBER: 3 # Increase to reset cache with: @@ -346,7 +346,7 @@ jobs: run: Get-Content -Path .\lockfile - name: Cache conda packages - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 env: CACHE_NUMBER: 0 # Increase to reset cache with: From ee98a006f8bf8dbead60f295bbb247055f9277dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 23:33:02 +0000 Subject: [PATCH 11/14] Bump actions/setup-python from 6.2.0 to 6.3.0 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.2.0 to 6.3.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/a309ff8b426b58ec0e2a45f0f869d46889d02405...ece7cb06caefa5fff74198d8649806c4678c61a1) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: 6.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build-with-clang.yml | 2 +- .github/workflows/pre-commit-autoupdate.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-with-clang.yml b/.github/workflows/build-with-clang.yml index d598ce3a..2c5d5f35 100644 --- a/.github/workflows/build-with-clang.yml +++ b/.github/workflows/build-with-clang.yml @@ -43,7 +43,7 @@ jobs: sudo apt-get install intel-oneapi-mkl-devel - name: Setup Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ matrix.python }} architecture: x64 diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml index af315865..277def47 100644 --- a/.github/workflows/pre-commit-autoupdate.yml +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Set up python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v5.6.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v5.6.0 with: python-version: '3.14' diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 9cce09ab..faf9c136 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -19,7 +19,7 @@ jobs: ref: ${{ github.sha }} - name: Set up python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: '3.14' From 34a938a6858ee4b5d9c0664f08735b453ac331d7 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Tue, 30 Jun 2026 12:06:05 +0200 Subject: [PATCH 12/14] Remove TODO comment from conda-forge receipe --- conda-recipe-cf/meta.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/conda-recipe-cf/meta.yaml b/conda-recipe-cf/meta.yaml index 29752718..0e54f381 100644 --- a/conda-recipe-cf/meta.yaml +++ b/conda-recipe-cf/meta.yaml @@ -30,9 +30,7 @@ requirements: - python - python-gil # [py>=314] - mkl-devel - - numpy # [not win] - - numpy <2.4 # [win] - # TODO: remove win numpy pin when numpy 2.5 is released, see https://github.com/numpy/numpy/issues/31337 + - numpy - llvm-openmp run: - python From 04bfc51e1d7859c6ccb8ec87c0ed6621e27bb5f3 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Tue, 30 Jun 2026 15:42:33 +0200 Subject: [PATCH 13/14] Backport 0.4.3 changelog entry from maintenance/0.4.x Record the 0.4.3 release on main and move the gh-226 entry from the unreleased [dev] section into the released [0.4.3] section, matching the finalized changelog on the maintenance/0.4.x branch. Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b129cdd..f6f52d87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,10 +11,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * Removed `numpy-base` dependency and `USE_NUMPY_BASE` environment variable from conda recipe [gh-200](https://github.com/IntelPython/mkl_umath/pull/200) -* Updated `mkl_umath` patching to work with changes to NumPy Cython API present in NumPy 2.5 [gh-226](https://github.com/IntelPython/mkl_umath/pull/226) ### Fixed +## [0.4.3] - 2026-06-30 + +### Changed +* Updated `mkl_umath` patching to work with changes to NumPy Cython API present in NumPy 2.5 [gh-226](https://github.com/IntelPython/mkl_umath/pull/226) + ## [0.4.2] - 2026-05-28 ### Added From 5b64315b293d9f7273a7c0b8f79cdfd8d31774b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 23:33:45 +0000 Subject: [PATCH 14/14] Bump github/codeql-action/upload-sarif from 4.36.2 to 4.36.3 Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 4.36.2 to 4.36.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...54f647b7e1bb85c95cddabcd46b0c578ec92bc1a) --- updated-dependencies: - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.36.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/openssf-scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openssf-scorecard.yml b/.github/workflows/openssf-scorecard.yml index e4d2f6dc..07342237 100644 --- a/.github/workflows/openssf-scorecard.yml +++ b/.github/workflows/openssf-scorecard.yml @@ -71,6 +71,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 + uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 with: sarif_file: results.sarif