diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0c8824ea..3485adfa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,24 +37,17 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - arch: [auto, aarch64, universal2] + os: [ubuntu-latest, windows-latest, macos-13, macos-14] + arch: [auto, aarch64] py: [cp38, cp39, cp310, cp311, cp312] exclude: - os: windows-latest arch: aarch64 - - os: windows-latest - arch: universal2 - - os: macos-latest + - os: macos-13 + arch: aarch64 + - os: macos-14 arch: aarch64 - - os: macos-latest - arch: auto - - os: ubuntu-latest - arch: universal2 - - env: - CIBW_BUILD: ${{ matrix.py }}-* - CIBW_ARCHS_LINUX: ${{ matrix.arch }} + steps: - uses: actions/checkout@v4 with: @@ -63,7 +56,7 @@ jobs: - if: ${{ matrix.arch == 'aarch64' }} uses: docker/setup-qemu-action@v3 - - uses: pypa/cibuildwheel@v2.16.5 + - uses: pypa/cibuildwheel@v2.17.0 env: CIBW_BUILD: ${{ matrix.py }}-* CIBW_ARCHS: ${{ matrix.arch }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 09358f3d..7ead82e4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,15 +18,19 @@ jobs: strategy: matrix: - os: [windows-latest, macos-latest, ubuntu-latest] include: # version number must be string, otherwise 3.10 becomes 3.1 - os: windows-latest python-version: "3.11" + installs: "numpy>=2.0.0rc1" - os: macos-latest python-version: "3.8" + installs: "'numpy==1.21.0'" - os: ubuntu-latest python-version: "pypy-3.8" + - os: ubuntu-latest + python-version: "3.12" + installs: "'numpy>=2.0.0rc1' scipy matplotlib" fail-fast: false steps: - uses: actions/checkout@v4 @@ -41,8 +45,8 @@ jobs: python-version: ${{ matrix.python-version }} - run: python -m pip install --upgrade pip wheel # python -m pip install .[test] is not used here to test minimum (faster), - # the cov workflow runs all tests - - run: python -m pip install -v . pytest + # the cov workflow runs all tests. + - run: python -m pip install -v . pytest ${{ matrix.installs }} - run: python -m pytest # aarch64: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 809ae738..cdb55de0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -68,3 +68,14 @@ repos: additional_dependencies: [numpy] args: [src] pass_filenames: false + +- repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.28.0 + hooks: + - id: check-readthedocs + - id: check-github-workflows + +- repo: https://github.com/henryiii/validate-pyproject-schema-store + rev: 2024.03.25 + hooks: + - id: validate-pyproject diff --git a/doc/notebooks/hesse_and_minos.ipynb b/doc/notebooks/hesse_and_minos.ipynb index a400fad8..3978268a 100644 --- a/doc/notebooks/hesse_and_minos.ipynb +++ b/doc/notebooks/hesse_and_minos.ipynb @@ -1,5 +1,5 @@ { - "cells": [ + "cells": [ { "attachments": {}, "cell_type": "markdown", diff --git a/pyproject.toml b/pyproject.toml index 2fdfff1f..ef4ed0db 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["scikit-build-core[pyproject]>=0.3", "pybind11"] +requires = ["scikit-build-core[pyproject]>=0.5", "pybind11>=2.12"] build-backend = "scikit_build_core.build" [project] @@ -33,7 +33,7 @@ classifiers = [ "Operating System :: Unix", "Operating System :: MacOS", ] -dependencies = ["numpy >= 1.21", "typing_extensions;python_version < '3.9'"] +dependencies = ["numpy >=1.21", "typing_extensions >=3.7.4; python_version<'3.9'"] [project.urls] repository = "http://github.com/scikit-hep/iminuit" @@ -75,7 +75,7 @@ doc = [ ] [tool.scikit-build] -minimum-version = "0.3" +minimum-version = "0.5" build-dir = "build/{wheel_tag}" sdist.exclude = ["extern/root"] sdist.include = ["extern/root/math/minuit2/inc", "extern/root/math/minuit2/src"] @@ -87,7 +87,7 @@ log_cli_level = "INFO" testpaths = ["tests"] xfail_strict = true filterwarnings = [ - "error::numpy.VisibleDeprecationWarning", + "error::iminuit._exceptions.VisibleDeprecationWarning", "error::PendingDeprecationWarning", "error::DeprecationWarning", "error::FutureWarning", @@ -126,7 +126,7 @@ no_implicit_optional = false [tool.cibuildwheel] # update skip when numpy wheels become available -skip = ["*-musllinux_*", "cp31?-win32", "cp31?-manylinux_i686"] +skip = ["*-musllinux_*", "cp31?-manylinux_i686"] test-requires = "pytest" test-command = "python -m pytest {package}/tests" test-skip = ["*universal2:arm64"] diff --git a/src/iminuit/_deprecated.py b/src/iminuit/_deprecated.py index bd6a369f..6331d41d 100644 --- a/src/iminuit/_deprecated.py +++ b/src/iminuit/_deprecated.py @@ -1,5 +1,5 @@ import warnings -from numpy import VisibleDeprecationWarning +from ._exceptions import VisibleDeprecationWarning class deprecated: diff --git a/src/iminuit/_exceptions.py b/src/iminuit/_exceptions.py new file mode 100644 index 00000000..e6ede410 --- /dev/null +++ b/src/iminuit/_exceptions.py @@ -0,0 +1,7 @@ +# NumPy 2 and recent 1.x place this in exceptions +try: + from numpy.exceptions import VisibleDeprecationWarning +except ImportError: + from numpy import VisibleDeprecationWarning + +__all__ = ["VisibleDeprecationWarning"] diff --git a/src/iminuit/cost.py b/src/iminuit/cost.py index 1bb943e9..5710f79a 100644 --- a/src/iminuit/cost.py +++ b/src/iminuit/cost.py @@ -92,6 +92,7 @@ class documentation for details. is_positive_definite, ) from .typing import Model, ModelGradient, LossFunction +from ._exceptions import VisibleDeprecationWarning import numpy as np from numpy.typing import NDArray, ArrayLike from collections.abc import Sequence as ABCSequence @@ -1521,7 +1522,7 @@ def __init__(self, n, xe, model, verbose, grad, use_pdf): self._model_xm = self._model_xe[:-1] + 0.5 * dx else: self._xe_shape = tuple(len(xei) for xei in self.xe) - self._model_xe = np.row_stack( + self._model_xe = np.vstack( [x.flatten() for x in np.meshgrid(*self.xe, indexing="ij")] ) if use_pdf == "approximate": @@ -1754,7 +1755,7 @@ def __init__( if method == "hpd": warnings.warn( "key 'hpd' is deprecated, please use 'da' instead", - category=np.VisibleDeprecationWarning, + category=VisibleDeprecationWarning, stacklevel=2, ) @@ -1765,7 +1766,7 @@ def __init__( self._model_xe = _norm(self.xe) else: self._xe_shape = tuple(len(xei) for xei in self.xe) - self._model_xe = np.row_stack( + self._model_xe = np.vstack( [x.flatten() for x in np.meshgrid(*self.xe, indexing="ij")] ) self._model_len = np.prod(self._xe_shape) @@ -2473,7 +2474,11 @@ def _normalize_output(x, kind, *shape, msg=None): if x.ndim < len(shape): return x.reshape(*shape) elif x.shape != shape: - msg = f"output of {kind} has shape {x.shape!r}, but {shape!r} is required" + # NumPy 2 uses a numpy int here + pretty_shape = tuple(int(i) for i in shape) + msg = ( + f"output of {kind} has shape {x.shape!r}, but {pretty_shape!r} is required" + ) raise ValueError(msg) return x @@ -2504,7 +2509,7 @@ def __getattr__(name: str) -> Any: new_name, obj = _deprecated_content[name] warnings.warn( f"{name} was renamed to {new_name}, please import {new_name} instead", - np.VisibleDeprecationWarning, + VisibleDeprecationWarning, stacklevel=2, ) return obj diff --git a/tests/test_cost.py b/tests/test_cost.py index 77b17bb9..b810dc25 100644 --- a/tests/test_cost.py +++ b/tests/test_cost.py @@ -18,6 +18,7 @@ ) from iminuit.util import describe from iminuit.typing import Annotated, Gt, Lt +from iminuit._exceptions import VisibleDeprecationWarning from typing import Sequence import pickle @@ -320,9 +321,7 @@ def test_UnbinnedNLL_visualize(log): # manual spacing c.visualize((1, 2), model_points=np.linspace(1, 1000)) - with pytest.warns( - np.VisibleDeprecationWarning, match="keyword 'nbins' is deprecated" - ): + with pytest.warns(VisibleDeprecationWarning, match="keyword 'nbins' is deprecated"): c.visualize((1, 2), nbins=20) @@ -1909,15 +1908,15 @@ def test_Template_pulls(): def test_deprecated(): from iminuit import cost - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): from iminuit.cost import BarlowBeestonLite assert BarlowBeestonLite is cost.Template - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): from iminuit.cost import barlow_beeston_lite_chi2_jsc assert barlow_beeston_lite_chi2_jsc is cost.template_chi2_jsc - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): from iminuit.cost import barlow_beeston_lite_chi2_hpd assert barlow_beeston_lite_chi2_hpd is cost.template_chi2_da @@ -1925,7 +1924,7 @@ def test_deprecated(): def test_deprecated_Template_method(): from iminuit import cost - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): t = Template([1], [2, 3], [[1], [2]], method="hpd") t._impl is cost.template_chi2_da @@ -1967,7 +1966,7 @@ def cdf(xye, a): def test_BohmZechTransform(): from iminuit.cost import BohmZechTransform - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): val = np.array([1.0, 2.0]) var = np.array([3.0, 4.0]) tr = BohmZechTransform(val, var) diff --git a/tests/test_deprecated.py b/tests/test_deprecated.py index 5746a159..7f530d79 100644 --- a/tests/test_deprecated.py +++ b/tests/test_deprecated.py @@ -1,6 +1,6 @@ from iminuit._deprecated import deprecated, deprecated_parameter +from iminuit._exceptions import VisibleDeprecationWarning import pytest -import numpy as np def test_deprecated_func(): @@ -8,7 +8,7 @@ def test_deprecated_func(): def func(x): pass - with pytest.warns(np.VisibleDeprecationWarning, match="func is deprecated: bla"): + with pytest.warns(VisibleDeprecationWarning, match="func is deprecated: bla"): func(1) @@ -20,7 +20,7 @@ def some_function(x, y, foo): some_function(1, 2, foo=3) with pytest.warns( - np.VisibleDeprecationWarning, + VisibleDeprecationWarning, match="keyword 'bar' is deprecated, please use 'foo'", ): some_function(1, 2, bar=3) diff --git a/tests/test_describe.py b/tests/test_describe.py index 9a04e963..2545cc2f 100644 --- a/tests/test_describe.py +++ b/tests/test_describe.py @@ -1,5 +1,6 @@ from iminuit.util import describe, make_func_code from iminuit.typing import Annotated, Gt, Lt, Ge, Le, Interval +from iminuit._exceptions import VisibleDeprecationWarning from math import ldexp import platform from functools import wraps @@ -94,7 +95,7 @@ def __init__(self): def __call__(self, *args): pass - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): assert describe(A()) == ["x", "y"] diff --git a/tests/test_minuit.py b/tests/test_minuit.py index 5fa9cb66..b70ab6c9 100644 --- a/tests/test_minuit.py +++ b/tests/test_minuit.py @@ -6,6 +6,7 @@ from iminuit.util import Param, make_func_code from iminuit.warnings import IMinuitWarning, ErrordefAlreadySetWarning from iminuit.typing import Annotated +from iminuit._exceptions import VisibleDeprecationWarning from pytest import approx from argparse import Namespace @@ -193,7 +194,7 @@ def test_Func1(): def test_Func2(): - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): func_test_helper(Func2()) diff --git a/tests/test_util.py b/tests/test_util.py index 793f3472..74f34329 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -7,6 +7,7 @@ from iminuit._optional_dependencies import optional_module_for import pickle from iminuit._hide_modules import hide_modules +from iminuit._exceptions import VisibleDeprecationWarning try: import scipy # noqa @@ -450,12 +451,12 @@ def fcn(y, x): def test_make_func_code(): - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): fc = util.make_func_code(["a", "b"]) assert fc.co_varnames == ("a", "b") assert fc.co_argcount == 2 - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): fc = util.make_func_code(("x",)) assert fc.co_varnames == ("x",) assert fc.co_argcount == 1 @@ -530,14 +531,14 @@ def test_propagate_1(): def fn(x): return 2 * x + 1 - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): y, ycov = util.propagate(fn, x, cov) np.testing.assert_allclose(y, [3, 5, 7]) np.testing.assert_allclose( ycov, [[4, 0.4, 0.8], [0.4, 8, 1.2], [0.8, 1.2, 12]], rtol=1e-3 ) - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): y, ycov = util.propagate(fn, [1], [[2]]) np.testing.assert_allclose(y, 3) np.testing.assert_allclose(ycov, 8, rtol=1e-3) @@ -557,7 +558,7 @@ def test_propagate_2(): def fn(x): return np.dot(a, x) - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): y, ycov = util.propagate(fn, x, cov) np.testing.assert_equal(y, fn(x)) np.testing.assert_allclose(ycov, np.einsum("ij,kl,jl", a, a, cov), rtol=1e-3) @@ -565,7 +566,7 @@ def fn(x): def fn(x): return np.linalg.multi_dot([x.T, cov, x]) - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): y, ycov = util.propagate(fn, x, cov) np.testing.assert_equal(y, fn(np.array(x))) jac = 2 * np.dot(cov, x) @@ -585,7 +586,7 @@ def test_propagate_3(): def fn(x): return 2 * x + 1 - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): y, ycov = util.propagate(fn, x, cov) np.testing.assert_allclose(y, [3, 5, 7]) np.testing.assert_allclose(ycov, [[4, 0.0, 0.8], [0.0, 0.0, 0.0], [0.8, 0.0, 12]]) @@ -599,16 +600,16 @@ def test_propagate_on_bad_input(): def fn(x): return 2 * x + 1 - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): with pytest.raises(ValueError): util.propagate(fn, x, cov) - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): with pytest.raises(ValueError): util.propagate(fn, x, 1) cov = [[1.0], [1.0]] - with pytest.warns(np.VisibleDeprecationWarning): + with pytest.warns(VisibleDeprecationWarning): with pytest.raises(ValueError): util.propagate(fn, x, cov)