From d68c16017bfddf9297dfb56687e6c40aa018eced Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Wed, 29 May 2024 19:08:49 +0530 Subject: [PATCH 01/25] FIX: Disable `pytest` caching The pytest test suite is trying to generate additional files and it tries to save them to a filesystem that is for some reason read-only. Since this workflow runs only in a temporary CI job, the `.pyc` file generation can be disabled. Some other fixes are included as well: 1. pydantic<2 not needed anymore 2. Skip the job on forks 3. More readable condition for Anaconda upload step --- .github/workflows/emscripten.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 646904574..3281c99b4 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -30,8 +30,8 @@ jobs: build_wasm_emscripten: name: Build PyWavelets for Pyodide runs-on: ubuntu-latest - # Uncomment the following line to test changes on a fork - # if: github.repository == 'PyWavelets/pywt' + # Comment out the following line to test changes on a fork + if: github.repository == 'PyWavelets/pywt' steps: - name: Check out repository uses: actions/checkout@v4 @@ -44,7 +44,7 @@ jobs: - name: Install prerequisites run: | - python -m pip install pyodide-build "pydantic<2" + python -m pip install pyodide-build echo EMSCRIPTEN_VERSION=$(pyodide config get emscripten_version) >> $GITHUB_ENV - name: Set up Emscripten toolchain @@ -70,12 +70,16 @@ jobs: pushd demo pip install matplotlib pytest python -c "import pywt; print(pywt.__version__)" - pytest --pyargs pywt -m "not slow" + pytest -p no:cacheprovider --pyargs pywt -m "not slow" # https://anaconda.org/scientific-python-nightly-wheels/pywavelets # WARNING: this job will overwrite existing wheels. - name: Push to Anaconda PyPI index - if: (github.repository == 'PyWavelets/pywt') && (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_wheels == 'true') || (github.event_name == 'schedule') + if: >- + (github.repository == 'PyWavelets/pywt') && + (github.event_name == 'push' && github.ref == 'refs/heads/main') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.push_wheels == 'true') || + (github.event_name == 'schedule') uses: scientific-python/upload-nightly-action@b67d7fcc0396e1128a474d1ab2b48aa94680f9fc # v0.5.0 with: artifacts_path: dist/ From 8950c7e821f9a018e2f1908234cfceb818a4cdf5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 2 Jun 2024 11:08:26 +0200 Subject: [PATCH 02/25] Bump the github-actions group with 2 updates (#745) Bumps the github-actions group with 2 updates: [pypa/cibuildwheel](/~https://github.com/pypa/cibuildwheel) and [softprops/action-gh-release](/~https://github.com/softprops/action-gh-release). Updates `pypa/cibuildwheel` from 2.17.0 to 2.18.1 - [Release notes](/~https://github.com/pypa/cibuildwheel/releases) - [Changelog](/~https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](/~https://github.com/pypa/cibuildwheel/compare/8d945475ac4b1aac4ae08b2fd27db9917158b6ce...ba8be0d98853f5744f24e7f902c8adef7ae2e7f3) Updates `softprops/action-gh-release` from 2.0.4 to 2.0.5 - [Release notes](/~https://github.com/softprops/action-gh-release/releases) - [Changelog](/~https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](/~https://github.com/softprops/action-gh-release/compare/9d7c94cfd0a1f3ed45544c887983e9fa900f0564...69320dbe05506a9a39fc8ae11030b214ec2d1f87) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: softprops/action-gh-release dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheel_tests_and_release.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index 61f904e15..fcef94f03 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -45,7 +45,7 @@ jobs: with: python-version: "3.10" - name: Build the wheel - uses: pypa/cibuildwheel@8d945475ac4b1aac4ae08b2fd27db9917158b6ce # 2.17.0 + uses: pypa/cibuildwheel@ba8be0d98853f5744f24e7f902c8adef7ae2e7f3 # 2.18.1 with: output-dir: dist env: @@ -81,7 +81,7 @@ jobs: with: platforms: arm64 - name: Build the wheel - uses: pypa/cibuildwheel@8d945475ac4b1aac4ae08b2fd27db9917158b6ce # 2.17.0 + uses: pypa/cibuildwheel@ba8be0d98853f5744f24e7f902c8adef7ae2e7f3 # 2.18.1 with: output-dir: dist env: @@ -121,7 +121,7 @@ jobs: - name: Build wheels for CPython (macOS) (x86_64) if: matrix.cibw_arch == 'x86_64' - uses: pypa/cibuildwheel@8d945475ac4b1aac4ae08b2fd27db9917158b6ce # 2.17.0 + uses: pypa/cibuildwheel@ba8be0d98853f5744f24e7f902c8adef7ae2e7f3 # 2.18.1 with: output-dir: dist env: @@ -130,7 +130,7 @@ jobs: - name: Build wheels for CPython (macOS) (arm64) if: matrix.cibw_arch == 'arm64' - uses: pypa/cibuildwheel@8d945475ac4b1aac4ae08b2fd27db9917158b6ce # 2.17.0 + uses: pypa/cibuildwheel@ba8be0d98853f5744f24e7f902c8adef7ae2e7f3 # 2.18.1 with: output-dir: dist env: @@ -175,7 +175,7 @@ jobs: architecture: x64 - name: Build Windows wheels for CPython - uses: pypa/cibuildwheel@8d945475ac4b1aac4ae08b2fd27db9917158b6ce # 2.17.0 + uses: pypa/cibuildwheel@ba8be0d98853f5744f24e7f902c8adef7ae2e7f3 # 2.18.1 with: output-dir: dist env: @@ -237,7 +237,7 @@ jobs: TWINE_PASSWORD: ${{ secrets.TWINE_TOKEN }} - name: Github release - uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564 # v2.0.4 + uses: softprops/action-gh-release@69320dbe05506a9a39fc8ae11030b214ec2d1f87 # v2.0.5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} From 68ed81dadc5438dfe88e7a70e06ad9b4136fb95c Mon Sep 17 00:00:00 2001 From: Evgeni Burovski Date: Tue, 4 Jun 2024 09:19:10 +0300 Subject: [PATCH 03/25] DOC: easy_install is no longer a thing (#748) --- doc/source/dev/building_extension.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/dev/building_extension.rst b/doc/source/dev/building_extension.rst index 7c8bd817b..193e7cca4 100644 --- a/doc/source/dev/building_extension.rst +++ b/doc/source/dev/building_extension.rst @@ -40,6 +40,6 @@ or:: Installing a regular release from PyPi -------------------------------------- -A regular release can be installed with pip or easy_install:: +A regular release can be installed with pip:: pip install PyWavelets From 6dd3edeac0f0c46508b6ca1253d8deaf6c80b481 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Thu, 30 May 2024 17:27:15 +0530 Subject: [PATCH 04/25] CI. BLD: Use `cibuildwheel` for WASM/Pyodide builds --- .github/workflows/emscripten.yml | 47 ++++++-------------------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 3281c99b4..540c50462 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -29,52 +29,23 @@ env: jobs: build_wasm_emscripten: name: Build PyWavelets for Pyodide - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 # Comment out the following line to test changes on a fork if: github.repository == 'PyWavelets/pywt' steps: - name: Check out repository uses: actions/checkout@v4 - - name: Set up Python 3.11 - id: setup-python - uses: actions/setup-python@v5 - with: - python-version: "3.11.2" - - - name: Install prerequisites - run: | - python -m pip install pyodide-build - echo EMSCRIPTEN_VERSION=$(pyodide config get emscripten_version) >> $GITHUB_ENV - - - name: Set up Emscripten toolchain - uses: mymindstorm/setup-emsdk@v14 - with: - version: ${{ env.EMSCRIPTEN_VERSION }} - actions-cache-folder: emsdk-cache - - - name: Set up Node.js - uses: actions/setup-node@v4.0.2 - with: - node-version: "18" - - - name: Build PyWavelets - run: | - pyodide build - - - name: Install and test wheel - run: | - pyodide venv .venv-pyodide - source .venv-pyodide/bin/activate - pip install dist/*.whl - pushd demo - pip install matplotlib pytest - python -c "import pywt; print(pywt.__version__)" - pytest -p no:cacheprovider --pyargs pywt -m "not slow" + - name: Build and test PyWavelets + uses: pypa/cibuildwheel@v2.19.1 + env: + CIBW_PLATFORM: pyodide + CIBW_TEST_REQUIRES: pytest matplotlib + CIBW_TEST_COMMAND: python -c "import pywt; pywt.test(extra_argv=['-m', 'not slow'])" # https://anaconda.org/scientific-python-nightly-wheels/pywavelets # WARNING: this job will overwrite existing wheels. - - name: Push to Anaconda PyPI index + - name: Push wheels to Anaconda PyPI index if: >- (github.repository == 'PyWavelets/pywt') && (github.event_name == 'push' && github.ref == 'refs/heads/main') || @@ -82,5 +53,5 @@ jobs: (github.event_name == 'schedule') uses: scientific-python/upload-nightly-action@b67d7fcc0396e1128a474d1ab2b48aa94680f9fc # v0.5.0 with: - artifacts_path: dist/ + artifacts_path: wheelhouse/ anaconda_nightly_upload_token: ${{ secrets.ANACONDA_ORG_UPLOAD_TOKEN }} From f2b3d58145bb94f07e213b0c18de22ff859d21e5 Mon Sep 17 00:00:00 2001 From: Evgeni Burovski Date: Tue, 25 Jun 2024 18:25:44 +0300 Subject: [PATCH 05/25] MAINT: use `scipy-doctest` instead of `refguide-check` (#747) $ pytest --doctest-modules --pyargs pywt -v --doctest-collect=api ... pywt/__init__.py::pywt.ContinuousWavelet.wavefun PASSED [ 3%] pywt/__init__.py::pywt.Modes PASSED [ 6%] pywt/__init__.py::pywt.Wavelet.wavefun PASSED [ 9%] pywt/__init__.py::pywt.array_to_coeffs PASSED [ 12%] pywt/__init__.py::pywt.coeffs_to_array PASSED [ 16%] pywt/__init__.py::pywt.cwt PASSED [ 19%] pywt/__init__.py::pywt.dwt PASSED [ 22%] pywt/__init__.py::pywt.dwt2 PASSED [ 25%] pywt/__init__.py::pywt.dwt_max_level PASSED [ 29%] pywt/__init__.py::pywt.dwtn_max_level PASSED [ 32%] pywt/__init__.py::pywt.families PASSED [ 35%] pywt/__init__.py::pywt.fswavedecn PASSED [ 38%] pywt/__init__.py::pywt.idwt PASSED [ 41%] pywt/__init__.py::pywt.idwt2 PASSED [ 45%] pywt/__init__.py::pywt.integrate_wavelet PASSED [ 48%] pywt/__init__.py::pywt.iswt PASSED [ 51%] pywt/__init__.py::pywt.iswt2 PASSED [ 54%] pywt/__init__.py::pywt.iswtn PASSED [ 58%] pywt/__init__.py::pywt.ravel_coeffs PASSED [ 61%] pywt/__init__.py::pywt.threshold PASSED [ 64%] pywt/__init__.py::pywt.unravel_coeffs PASSED [ 67%] pywt/__init__.py::pywt.upcoef PASSED [ 70%] pywt/__init__.py::pywt.wavedec PASSED [ 74%] pywt/__init__.py::pywt.wavedec2 PASSED [ 77%] pywt/__init__.py::pywt.wavedecn PASSED [ 80%] pywt/__init__.py::pywt.wavedecn_shapes PASSED [ 83%] pywt/__init__.py::pywt.wavedecn_size PASSED [ 87%] pywt/__init__.py::pywt.wavelist PASSED [ 90%] pywt/__init__.py::pywt.waverec PASSED [ 93%] pywt/__init__.py::pywt.waverec2 PASSED [ 96%] pywt/__init__.py::pywt.waverecn PASSED [100%] ================================== 31 passed in 0.80s ===================== Makes this green: $ pytest --doctest-glob=*rst doc/source/regression/ -vs Removes `refguide-check.py` The script can do two things: - run modified doctests; this is done via smoke-docs / scipy-doctests now - check __all__ lists vs refguide entries; this was already disabled, on CI at least --- .github/workflows/tests.yml | 20 +- pywt/_cwt.py | 8 +- pywt/_extensions/_pywt.pyx | 32 +- pywt/_multilevel.py | 5 +- pywt/data/_readers.py | 20 +- pywt/data/_wavelab_signals.py | 5 +- util/refguide_check.py | 865 ---------------------------------- 7 files changed, 44 insertions(+), 911 deletions(-) delete mode 100755 util/refguide_check.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f84d04170..0ad1fd8f5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,7 +37,7 @@ jobs: MINIMUM_REQUIREMENTS: [0] USE_SCIPY: [0] USE_SDIST: [0] - REFGUIDE_CHECK: [0] + REFGUIDE_CHECK: [1] PIP_FLAGS: [""] OPTIONS_NAME: ["default"] include: @@ -105,7 +105,7 @@ jobs: python -m build --sdist pip install dist/pyw*.tar.gz -v elif [ "${REFGUIDE_CHECK}" == "1" ]; then - pip install sphinx numpydoc + pip install sphinx numpydoc scipy-doctest pip install . -v else pip install . -v @@ -129,11 +129,13 @@ jobs: pytest --pyargs pywt python ../pywt/tests/test_doc.py elif [ "${REFGUIDE_CHECK}" == "1" ]; then - # Run doctests and check if the refguide contains entries from __all__ - python util/refguide_check.py --doctests + # doctest docstrings + pytest --doctest-modules --pyargs pywt -v --doctest-collect=api # Run Sphinx HTML docs builder, converting warnings to errors - pip install -r util/readthedocs/requirements.txt - sphinx-build -b html -W --keep-going -d _build/doctrees . doc/source doc/build + cd .. + # XXX sphinx build is broken on CI + # pip install -r util/readthedocs/requirements.txt + # sphinx-build -b html -W --keep-going -d _build/doctrees . doc/source doc/build else pytest --pyargs pywt fi @@ -203,7 +205,7 @@ jobs: python -m build --sdist pip install pywavelets* -v elif [ "${REFGUIDE_CHECK}" == "1" ]; then - pip install sphinx numpydoc + pip install sphinx numpydoc scipy-doctest pip install . -v else pip install . -v @@ -221,7 +223,9 @@ jobs: pytest --pyargs pywt python ../pywt/tests/test_doc.py elif [ "${REFGUIDE_CHECK}" == "1" ]; then - python util/refguide_check.py --doctests + # doctests docstrings + pytest --doctest-modules --pyargs pywt -v --doctest-collect=api + pytest --doctest-modules --pyargs pywt.data -v else pytest --pyargs pywt fi diff --git a/pywt/_cwt.py b/pywt/_cwt.py index 161c4b340..5239e0e0a 100644 --- a/pywt/_cwt.py +++ b/pywt/_cwt.py @@ -94,8 +94,8 @@ def cwt(data, scales, wavelet, sampling_period=1., method='conv', axis=-1): >>> x = np.arange(512) >>> y = np.sin(2*np.pi*x/32) >>> coef, freqs=pywt.cwt(y,np.arange(1,129),'gaus1') - >>> plt.matshow(coef) # doctest: +SKIP - >>> plt.show() # doctest: +SKIP + >>> plt.matshow(coef) + >>> plt.show() >>> import pywt >>> import numpy as np @@ -105,8 +105,8 @@ def cwt(data, scales, wavelet, sampling_period=1., method='conv', axis=-1): >>> widths = np.arange(1, 31) >>> cwtmatr, freqs = pywt.cwt(sig, widths, 'mexh') >>> plt.imshow(cwtmatr, extent=[-1, 1, 1, 31], cmap='PRGn', aspect='auto', - ... vmax=abs(cwtmatr).max(), vmin=-abs(cwtmatr).max()) # doctest: +SKIP - >>> plt.show() # doctest: +SKIP + ... vmax=abs(cwtmatr).max(), vmin=-abs(cwtmatr).max()) + >>> plt.show() """ # accept array_like input; make a copy to ensure a contiguous array diff --git a/pywt/_extensions/_pywt.pyx b/pywt/_extensions/_pywt.pyx index 17e22cc92..fe448ca2d 100644 --- a/pywt/_extensions/_pywt.pyx +++ b/pywt/_extensions/_pywt.pyx @@ -85,7 +85,7 @@ class _Modes(object): -------- >>> import pywt >>> pywt.Modes.modes - ['zero', 'constant', 'symmetric', 'reflect', 'periodic', 'smooth', 'periodization', 'antisymmetric', 'antireflect'] + ['zero', 'constant', 'symmetric', 'periodic', 'smooth', 'periodization', 'reflect', 'antisymmetric', 'antireflect'] >>> # The different ways of passing wavelet and mode parameters >>> (a, d) = pywt.dwt([1,2,3,4,5,6], 'db2', 'smooth') >>> (a, d) = pywt.dwt([1,2,3,4,5,6], pywt.Wavelet('db2'), pywt.Modes.smooth) @@ -909,14 +909,13 @@ cdef public class ContinuousWavelet [type ContinuousWaveletType, object Continuo >>> wavelet.upper_bound = ub >>> wavelet.lower_bound = lb >>> [psi,xval] = wavelet.wavefun(length=n) - >>> plt.plot(xval,psi) # doctest: +ELLIPSIS - [] - >>> plt.title("Gaussian Wavelet of order 8") # doctest: +ELLIPSIS - - >>> plt.show() # doctest: +SKIP + >>> plt.plot(xval,psi) + >>> plt.title("Gaussian Wavelet of order 8") + >>> plt.show() - >>> import pywt + >>> import numpy as np >>> import matplotlib.pyplot as plt + >>> import pywt >>> lb = -5 >>> ub = 5 >>> n = 1000 @@ -924,19 +923,12 @@ cdef public class ContinuousWavelet [type ContinuousWaveletType, object Continuo >>> wavelet.upper_bound = ub >>> wavelet.lower_bound = lb >>> [psi,xval] = wavelet.wavefun(length=n) - >>> plt.subplot(211) # doctest: +ELLIPSIS - - >>> plt.plot(xval,np.real(psi)) # doctest: +ELLIPSIS - [] - >>> plt.title("Real part") # doctest: +ELLIPSIS - - >>> plt.subplot(212) # doctest: +ELLIPSIS - - >>> plt.plot(xval,np.imag(psi)) # doctest: +ELLIPSIS - [] - >>> plt.title("Imaginary part") # doctest: +ELLIPSIS - - >>> plt.show() # doctest: +SKIP + >>> fix, (ax1, ax2) = plt.subplots(2, 1) + >>> ax1.plot(xval,np.real(psi)) + >>> ax1.set_title("Real part") + >>> ax2.plot(xval,np.imag(psi)) + >>> ax2.set_title("Imaginary part") + >>> plt.show() """ cdef pywt_index_t output_length "output_length" diff --git a/pywt/_multilevel.py b/pywt/_multilevel.py index d6d26bf7f..0e5ca9cf1 100644 --- a/pywt/_multilevel.py +++ b/pywt/_multilevel.py @@ -402,7 +402,7 @@ def wavedecn(data, wavelet, mode='symmetric', level=None, axes=None): >>> # Levels: >>> len(coeffs)-1 2 - >>> waverecn(coeffs, 'db1') # doctest: +NORMALIZE_WHITESPACE + >>> waverecn(coeffs, 'db1') array([[[ 1., 1., 1., 1.], [ 1., 1., 1., 1.], [ 1., 1., 1., 1.], @@ -496,7 +496,7 @@ def waverecn(coeffs, wavelet, mode='symmetric', axes=None): >>> # Levels: >>> len(coeffs)-1 2 - >>> waverecn(coeffs, 'db1') # doctest: +NORMALIZE_WHITESPACE + >>> waverecn(coeffs, 'db1') array([[[ 1., 1., 1., 1.], [ 1., 1., 1., 1.], [ 1., 1., 1., 1.], @@ -1415,6 +1415,7 @@ def fswavedecn(data, wavelet, mode='symmetric', levels=None, axes=None): Examples -------- + >>> import numpy as np >>> from pywt import fswavedecn >>> fs_result = fswavedecn(np.ones((32, 32)), 'sym2', levels=(1, 3)) >>> print(fs_result.detail_keys()) diff --git a/pywt/data/_readers.py b/pywt/data/_readers.py index c7a52c6d0..8c2e7889c 100644 --- a/pywt/data/_readers.py +++ b/pywt/data/_readers.py @@ -36,9 +36,9 @@ def ascent(): >>> import matplotlib.pyplot as plt >>> plt.gray() - >>> plt.imshow(ascent) # doctest: +ELLIPSIS + >>> plt.imshow(ascent) - >>> plt.show() # doctest: +SKIP + >>> plt.show() """ with importlib.resources.as_file(_DATADIR.joinpath('ascent.npz')) as f: @@ -73,9 +73,9 @@ def aero(): >>> import matplotlib.pyplot as plt >>> plt.gray() - >>> plt.imshow(aero) # doctest: +ELLIPSIS + >>> plt.imshow(aero) - >>> plt.show() # doctest: +SKIP + >>> plt.show() """ with importlib.resources.as_file(_DATADIR.joinpath('aero.npz')) as f: @@ -121,9 +121,9 @@ def camera(): >>> import matplotlib.pyplot as plt >>> plt.gray() - >>> plt.imshow(camera) # doctest: +ELLIPSIS + >>> plt.imshow(camera) - >>> plt.show() # doctest: +SKIP + >>> plt.show() """ with importlib.resources.as_file(_DATADIR.joinpath('camera.npz')) as f: @@ -154,9 +154,9 @@ def ecg(): True >>> import matplotlib.pyplot as plt - >>> plt.plot(ecg) # doctest: +ELLIPSIS + >>> plt.plot(ecg) [] - >>> plt.show() # doctest: +SKIP + >>> plt.show() """ with importlib.resources.as_file(_DATADIR.joinpath('ecg.npz')) as f: ecg = np.load(f)['data'] @@ -192,9 +192,9 @@ def nino(): True >>> import matplotlib.pyplot as plt - >>> plt.plot(time,sst) # doctest: +ELLIPSIS + >>> plt.plot(time,sst) [] - >>> plt.show() # doctest: +SKIP + >>> plt.show() """ with importlib.resources.as_file(_DATADIR.joinpath('sst_nino3.npz')) as f: sst_csv = np.load(f)['data'] diff --git a/pywt/data/_wavelab_signals.py b/pywt/data/_wavelab_signals.py index 823d63231..952c0b9e5 100644 --- a/pywt/data/_wavelab_signals.py +++ b/pywt/data/_wavelab_signals.py @@ -70,8 +70,9 @@ def demo_signal(name='Bumps', n=None): >>> doppler = pywt.data.demo_signal('doppler', 1024) >>> available_signals = pywt.data.demo_signal('list') >>> print(available_signals) - - + ['Blocks', 'Bumps', 'HeaviSine', 'Doppler', 'Ramp', 'HiSine', 'LoSine', 'LinChirp', + 'TwoChirp', 'QuadChirp', 'MishMash', 'WernerSorrows', 'HypChirps', 'LinChirps', + 'Chirps', 'Gabor', 'sineoneoverx', 'Piece-Regular', 'Piece-Polynomial', 'Riemann'] """ if name.lower() == 'list': diff --git a/util/refguide_check.py b/util/refguide_check.py deleted file mode 100755 index 21750a48f..000000000 --- a/util/refguide_check.py +++ /dev/null @@ -1,865 +0,0 @@ -#!/usr/bin/env python -""" -refguide_check.py [OPTIONS] [-- ARGS] - -Check for a PyWavelets submodule whether the objects in its __all__ dict -correspond to the objects included in the reference guide. - -Example of usage:: - - $ python refguide_check.py optimize - -Note that this is a helper script to be able to check if things are missing; -the output of this script does need to be checked manually. In some cases -objects are left out of the refguide for a good reason (it's an alias of -another function, or deprecated, or ...) - -Another use of this helper script is to check validity of code samples -in docstrings. This is different from doctesting [we do not aim to have -scipy docstrings doctestable!], this is just to make sure that code in -docstrings is valid python:: - - $ python refguide_check.py --check_docs optimize - -""" - -import copy -import doctest -import glob -import inspect -import io -import os -import re -import shutil -import sys -import tempfile -import warnings -from argparse import ArgumentParser -from doctest import ELLIPSIS, IGNORE_EXCEPTION_DETAIL, NORMALIZE_WHITESPACE - -import docutils.core -import numpy as np -from docutils.parsers.rst import directives - -# FIXME: doctests need the str/repr formatting used in Numpy < 1.14. -try: - np.set_printoptions(legacy='1.13') -except TypeError: - pass - -# sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'doc', -# 'sphinxext')) -from numpydoc.docscrape_sphinx import get_doc_object - -# Remove sphinx directives that don't run without Sphinx environment -directives._directives.pop('versionadded', None) -directives._directives.pop('versionchanged', None) -directives._directives.pop('moduleauthor', None) -directives._directives.pop('sectionauthor', None) -directives._directives.pop('codeauthor', None) -directives._directives.pop('toctree', None) - - -BASE_MODULE = "pywt" - -PUBLIC_SUBMODULES = [] - -# Docs for these modules are included in the parent module -OTHER_MODULE_DOCS = {} - -# these names are known to fail doctesting and we like to keep it that way -# e.g. sometimes pseudocode is acceptable etc -DOCTEST_SKIPLIST = set() - -# these names are not required to be present in ALL despite being in -# autosummary:: listing -REFGUIDE_ALL_SKIPLIST = [] - -HAVE_MATPLOTLIB = False - - -def short_path(path, cwd=None): - """ - Return relative or absolute path name, whichever is shortest. - """ - if not isinstance(path, str): - return path - if cwd is None: - cwd = os.getcwd() - abspath = os.path.abspath(path) - relpath = os.path.relpath(path, cwd) - if len(abspath) <= len(relpath): - return abspath - return relpath - - -def find_names(module, names_dict): - # Refguide entries: - # - # - 3 spaces followed by function name, and maybe some spaces, some - # dashes, and an explanation; only function names listed in - # refguide are formatted like this (mostly, there may be some false - # positives) - # - # - special directives, such as data and function - # - # - (scipy.constants only): quoted list - # - patterns = [ - r"^\s\s\s([a-z_0-9A-Z]+)(\s+-+.*)?$", - r"^\.\. (?:data|function)::\s*([a-z_0-9A-Z]+)\s*$" - ] - - if module.__name__ == 'scipy.constants': - patterns += ["^``([a-z_0-9A-Z]+)``"] - - patterns = [re.compile(pattern) for pattern in patterns] - module_name = module.__name__ - - for line in module.__doc__.splitlines(): - res = re.search(r"^\s*\.\. (?:currentmodule|module):: ([a-z0-9A-Z_.]+)\s*$", line) - if res: - module_name = res.group(1) - continue - - for pattern in patterns: - res = re.match(pattern, line) - if res is not None: - name = res.group(1) - entry = '.'.join([module_name, name]) - names_dict.setdefault(module_name, set()).add(name) - break - - -def get_all_dict(module): - """Return a copy of the __all__ dict with irrelevant items removed.""" - if hasattr(module, "__all__"): - all_dict = copy.deepcopy(module.__all__) - else: - all_dict = copy.deepcopy(dir(module)) - all_dict = [name for name in all_dict - if not name.startswith("_")] - for name in ['absolute_import', 'division', 'print_function']: - try: - all_dict.remove(name) - except ValueError: - pass - - # Modules are almost always private; real submodules need a separate - # run of refguide_check. - all_dict = [name for name in all_dict - if not inspect.ismodule(getattr(module, name, None))] - - deprecated = [] - not_deprecated = [] - for name in all_dict: - f = getattr(module, name, None) - if callable(f) and is_deprecated(f): - deprecated.append(name) - else: - not_deprecated.append(name) - - others = set(dir(module)).difference(set(deprecated)).difference(set(not_deprecated)) - - return not_deprecated, deprecated, others - - -def compare(all_dict, others, names, module_name): - """Return sets of objects only in __all__, refguide, or completely missing.""" - only_all = set() - for name in all_dict: - if name not in names: - only_all.add(name) - - only_ref = set() - missing = set() - for name in names: - if name not in all_dict: - for pat in REFGUIDE_ALL_SKIPLIST: - if re.match(pat, module_name + '.' + name): - if name not in others: - missing.add(name) - break - else: - only_ref.add(name) - - return only_all, only_ref, missing - - -def is_deprecated(f): - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("error") - try: - f(**{"not a kwarg": None}) - except DeprecationWarning: - return True - except: - pass - return False - - -def check_items(all_dict, names, deprecated, others, module_name, dots=True): - num_all = len(all_dict) - num_ref = len(names) - - output = "" - - output += "Non-deprecated objects in __all__: %i\n" % num_all - output += "Objects in refguide: %i\n\n" % num_ref - - only_all, only_ref, missing = compare(all_dict, others, names, module_name) - dep_in_ref = set(only_ref).intersection(deprecated) - only_ref = set(only_ref).difference(deprecated) - - if len(dep_in_ref) > 0: - output += "Deprecated objects in refguide::\n\n" - for name in sorted(deprecated): - output += " " + name + "\n" - - if len(only_all) == len(only_ref) == len(missing) == 0: - if dots: - output_dot('.') - return [(None, True, output)] - else: - if len(only_all) > 0: - output += f"ERROR: objects in {module_name}.__all__ but not in refguide::\n\n" - for name in sorted(only_all): - output += " " + name + "\n" - - if len(only_ref) > 0: - output += f"ERROR: objects in refguide but not in {module_name}.__all__::\n\n" - for name in sorted(only_ref): - output += " " + name + "\n" - - if len(missing) > 0: - output += "ERROR: missing objects::\n\n" - for name in sorted(missing): - output += " " + name + "\n" - - if dots: - output_dot('F') - return [(None, False, output)] - - -def validate_rst_syntax(text, name, dots=True): - if text is None: - if dots: - output_dot('E') - return False, f"ERROR: {name}: no documentation" - - ok_unknown_items = { - 'mod', 'currentmodule', 'autosummary', 'data', - 'obj', 'versionadded', 'versionchanged', 'module', 'class', - 'ref', 'func', 'toctree', 'moduleauthor', - 'sectionauthor', 'codeauthor', 'eq', - } - - # Run through docutils - error_stream = io.StringIO() - - def resolve(name, is_label=False): - return ("http://foo", name) - - token = '' - - docutils.core.publish_doctree( - text, token, - settings_overrides = {'halt_level': 5, - 'traceback': True, - 'default_reference_context': 'title-reference', - 'default_role': 'emphasis', - 'link_base': '', - 'resolve_name': resolve, - 'stylesheet_path': '', - 'raw_enabled': 0, - 'file_insertion_enabled': 0, - 'warning_stream': error_stream}) - - # Print errors, disregarding unimportant ones - error_msg = error_stream.getvalue() - errors = error_msg.split(token) - success = True - output = "" - - for error in errors: - lines = error.splitlines() - if not lines: - continue - - m = re.match(r'.*Unknown (?:interpreted text role|directive type) "(.*)".*$', lines[0]) - if m: - if m.group(1) in ok_unknown_items: - continue - - m = re.match(r'.*Error in "math" directive:.*unknown option: "label"', " ".join(lines), re.S) - if m: - continue - - output += name + lines[0] + "::\n " + "\n ".join(lines[1:]).rstrip() + "\n" - success = False - - if not success: - output += " " + "-"*72 + "\n" - for lineno, line in enumerate(text.splitlines()): - output += " %-4d %s\n" % (lineno+1, line) - output += " " + "-"*72 + "\n\n" - - if dots: - output_dot('.' if success else 'F') - return success, output - - -def output_dot(msg='.', stream=sys.stderr): - stream.write(msg) - stream.flush() - - -def check_rest(module, names, dots=True): - """ - Check reStructuredText formatting of docstrings - - Returns: [(name, success_flag, output), ...] - """ - - try: - skip_types = (dict, str, unicode, float, int) - except NameError: - # python 3 - skip_types = (dict, str, float, int) - - results = [] - - if module.__name__[6:] not in OTHER_MODULE_DOCS: - results += [(module.__name__,) + - validate_rst_syntax(inspect.getdoc(module), - module.__name__, dots=dots)] - - for name in names: - full_name = module.__name__ + '.' + name - obj = getattr(module, name, None) - - if obj is None: - results.append((full_name, False, f"{full_name} has no docstring")) - continue - elif isinstance(obj, skip_types): - continue - - if inspect.ismodule(obj): - text = inspect.getdoc(obj) - else: - try: - text = str(get_doc_object(obj)) - except: - import traceback - results.append((full_name, False, - "Error in docstring format!\n" + - traceback.format_exc())) - continue - - m = re.search("([\x00-\x09\x0b-\x1f])", text) - if m: - msg = (f"Docstring contains a non-printable character {m.group(1)!r}! " - "Maybe forgot r\"\"\"?") - results.append((full_name, False, msg)) - continue - - try: - src_file = short_path(inspect.getsourcefile(obj)) - except TypeError: - src_file = None - - if src_file: - file_full_name = src_file + ':' + full_name - else: - file_full_name = full_name - - results.append((full_name,) + - validate_rst_syntax(text, file_full_name, dots=dots)) - - return results - - -### Doctest helpers #### - -# the namespace to run examples in -DEFAULT_NAMESPACE = {'np': np} - -# the namespace to do checks in -CHECK_NAMESPACE = { - 'np': np, - 'assert_allclose': np.testing.assert_allclose, - 'assert_equal': np.testing.assert_equal, - # recognize numpy repr's - 'array': np.array, - 'matrix': np.matrix, - 'int64': np.int64, - 'uint64': np.uint64, - 'int8': np.int8, - 'int32': np.int32, - 'float64': np.float64, - 'dtype': np.dtype, - 'nan': np.nan, - 'NaN': np.nan, - 'inf': np.inf, - 'Inf': np.inf, } - - -class DTRunner(doctest.DocTestRunner): - DIVIDER = "\n" - - def __init__(self, item_name, checker=None, verbose=None, optionflags=0): - self._item_name = item_name - doctest.DocTestRunner.__init__(self, checker=checker, verbose=verbose, - optionflags=optionflags) - - def _report_item_name(self, out, new_line=False): - if self._item_name is not None: - if new_line: - out("\n") - self._item_name = None - - def report_start(self, out, test, example): - self._checker._source = example.source - return doctest.DocTestRunner.report_start(self, out, test, example) - - def report_success(self, out, test, example, got): - if self._verbose: - self._report_item_name(out, new_line=True) - return doctest.DocTestRunner.report_success( - self, out, test, example, got) - - def report_unexpected_exception(self, out, test, example, exc_info): - self._report_item_name(out) - return doctest.DocTestRunner.report_unexpected_exception( - self, out, test, example, exc_info) - - def report_failure(self, out, test, example, got): - self._report_item_name(out) - return doctest.DocTestRunner.report_failure(self, out, test, - example, got) - -class Checker(doctest.OutputChecker): - obj_pattern = re.compile('at 0x[0-9a-fA-F]+>') - vanilla = doctest.OutputChecker() - rndm_markers = {'# random', '# Random', '#random', '#Random', "# may vary"} - stopwords = {'plt.', '.hist', '.show', '.ylim', '.subplot(', - 'set_title', 'imshow', 'plt.show', 'ax.axis', 'plt.plot(', - '.bar(', '.title', '.ylabel', '.xlabel', 'set_ylim', - 'set_xlim', '# reformatted'} - - def __init__(self, parse_namedtuples=True, ns=None, atol=1e-8, rtol=1e-2): - self.parse_namedtuples = parse_namedtuples - self.atol, self.rtol = atol, rtol - if ns is None: - self.ns = dict(CHECK_NAMESPACE) - else: - self.ns = ns - - def check_output(self, want, got, optionflags): - # cut it short if they are equal - if want == got: - return True - - # skip stopwords in source - if any(word in self._source for word in self.stopwords): - return True - - # skip random stuff - if any(word in want for word in self.rndm_markers): - return True - - # skip function/object addresses - if self.obj_pattern.search(got): - return True - - # ignore comments (e.g. signal.freqresp) - if want.lstrip().startswith("#"): - return True - - # try the standard doctest - try: - if self.vanilla.check_output(want, got, optionflags): - return True - except Exception: - pass - - # OK then, convert strings to objects - try: - a_want = eval(want, dict(self.ns)) - a_got = eval(got, dict(self.ns)) - except: - if not self.parse_namedtuples: - return False - # suppose that "want" is a tuple, and "got" is smth like - # MoodResult(statistic=10, pvalue=0.1). - # Then convert the latter to the tuple (10, 0.1), - # and then compare the tuples. - try: - num = len(a_want) - regex = ('[\w\d_]+\(' + - ', '.join(['[\w\d_]+=(.+)']*num) + - '\)') - grp = re.findall(regex, got.replace('\n', ' ')) - if len(grp) > 1: # no more than one for now - return False - # fold it back to a tuple - got_again = '(' + ', '.join(grp[0]) + ')' - return self.check_output(want, got_again, optionflags) - except Exception: - return False - - # ... and defer to numpy - try: - return self._do_check(a_want, a_got) - except Exception: - # heterog tuple, eg (1, np.array([1., 2.])) - try: - return all(self._do_check(w, g) for w, g in zip(a_want, a_got)) - except (TypeError, ValueError): - return False - - def _do_check(self, want, got): - # This should be done exactly as written to correctly handle all of - # numpy-comparable objects, strings, and heterogeneous tuples - try: - if want == got: - return True - except Exception: - pass - return np.allclose(want, got, atol=self.atol, rtol=self.rtol) - - -def _run_doctests(tests, full_name, verbose, doctest_warnings): - """Run modified doctests for the set of `tests`. - - Returns: list of [(success_flag, output), ...] - """ - flags = NORMALIZE_WHITESPACE | ELLIPSIS | IGNORE_EXCEPTION_DETAIL - runner = DTRunner(full_name, checker=Checker(), optionflags=flags, - verbose=verbose) - - output = [] - success = True - def out(msg): - output.append(msg) - - class MyStderr: - """Redirect stderr to the current stdout""" - def write(self, msg): - if doctest_warnings: - sys.stdout.write(msg) - else: - out(msg) - - # Run tests, trying to restore global state afterward - old_printoptions = np.get_printoptions() - old_errstate = np.seterr() - old_stderr = sys.stderr - cwd = os.getcwd() - tmpdir = tempfile.mkdtemp() - sys.stderr = MyStderr() - try: - os.chdir(tmpdir) - - # try to ensure random seed is NOT reproducible - np.random.seed(None) - - for t in tests: - t.filename = short_path(t.filename, cwd) - fails, successes = runner.run(t, out=out) - if fails > 0: - success = False - finally: - sys.stderr = old_stderr - os.chdir(cwd) - shutil.rmtree(tmpdir) - np.set_printoptions(**old_printoptions) - np.seterr(**old_errstate) - - return success, output - - -def check_doctests(module, verbose, ns=None, - dots=True, doctest_warnings=False): - """Check code in docstrings of the module's public symbols. - - Returns: list of [(item_name, success_flag, output), ...] - """ - if ns is None: - ns = dict(DEFAULT_NAMESPACE) - - # Loop over non-deprecated items - results = [] - - for name in get_all_dict(module)[0]: - full_name = module.__name__ + '.' + name - - if full_name in DOCTEST_SKIPLIST: - continue - - try: - obj = getattr(module, name) - except AttributeError: - import traceback - results.append((full_name, False, - "Missing item!\n" + - traceback.format_exc())) - continue - - finder = doctest.DocTestFinder() - try: - tests = finder.find(obj, name, globs=dict(ns)) - except: - import traceback - results.append((full_name, False, - "Failed to get doctests!\n" + - traceback.format_exc())) - continue - - success, output = _run_doctests(tests, full_name, verbose, - doctest_warnings) - - if dots: - output_dot('.' if success else 'F') - - results.append((full_name, success, "".join(output))) - - if HAVE_MATPLOTLIB: - import matplotlib.pyplot as plt - plt.close('all') - - return results - - -def check_doctests_testfile(fname, verbose, ns=None, - dots=True, doctest_warnings=False): - """Check code in a text file. - - Mimic `check_doctests` above, differing mostly in test discovery. - (which is borrowed from stdlib's doctest.testfile here, - /~https://github.com/python-git/python/blob/master/Lib/doctest.py) - - Returns: list of [(item_name, success_flag, output), ...] - - Notes - ----- - - We also try to weed out pseudocode: - * We maintain a list of exceptions which signal pseudocode, - * We split the text file into "blocks" of code separated by empty lines - and/or intervening text. - * If a block contains a marker, the whole block is then assumed to be - pseudocode. It is then not being doctested. - - The rationale is that typically, the text looks like this: - - blah - - >>> from numpy import some_module # pseudocode! - >>> func = some_module.some_function - >>> func(42) # still pseudocode - 146 - - blah - - >>> 2 + 3 # real code, doctest it - 5 - - """ - results = [] - - if ns is None: - ns = dict(DEFAULT_NAMESPACE) - - _, short_name = os.path.split(fname) - if short_name in DOCTEST_SKIPLIST: - return results - - full_name = fname - text = open(fname).read() - - PSEUDOCODE = {'some_function', 'some_module', 'import example', - 'ctypes.CDLL', # likely need compiling, skip it - 'integrate.nquad(func,' # ctypes integrate tutotial - } - - # split the text into "blocks" and try to detect and omit pseudocode blocks. - parser = doctest.DocTestParser() - good_parts = [] - for part in text.split('\n\n'): - tests = parser.get_doctest(part, ns, fname, fname, 0) - if any(word in ex.source for word in PSEUDOCODE - for ex in tests.examples): - # omit it - pass - else: - # `part` looks like a good code, let's doctest it - good_parts += [part] - - # Reassemble the good bits and doctest them: - good_text = '\n\n'.join(good_parts) - tests = parser.get_doctest(good_text, ns, fname, fname, 0) - success, output = _run_doctests([tests], full_name, verbose, - doctest_warnings) - - if dots: - output_dot('.' if success else 'F') - - results.append((full_name, success, "".join(output))) - - if HAVE_MATPLOTLIB: - import matplotlib.pyplot as plt - plt.close('all') - - return results - - -def init_matplotlib(): - global HAVE_MATPLOTLIB - - try: - import matplotlib - matplotlib.use('Agg') - HAVE_MATPLOTLIB = True - except ImportError: - HAVE_MATPLOTLIB = False - - -def main(argv): - parser = ArgumentParser(usage=__doc__.lstrip()) - parser.add_argument("module_names", metavar="SUBMODULES", default=[], - nargs='*', - help="Submodules to check (default: all public)") - parser.add_argument("--doctests", action="store_true", - help="Run also doctests") - parser.add_argument("-v", "--verbose", action="count", default=0) - parser.add_argument("--doctest-warnings", action="store_true", - help="Enforce warning checking for doctests") - parser.add_argument("--skip-examples", action="store_true", - help="Skip running doctests in the examples.") - args = parser.parse_args(argv) - - modules = [] - names_dict = {} - - if args.module_names: - args.skip_examples = True - else: - args.module_names = list(PUBLIC_SUBMODULES) - - os.environ['SCIPY_PIL_IMAGE_VIEWER'] = 'true' - - module_names = list(args.module_names) - for name in list(module_names): - if name in OTHER_MODULE_DOCS: - name = OTHER_MODULE_DOCS[name] - if name not in module_names: - module_names.append(name) - - for submodule_name in module_names: - module_name = BASE_MODULE + '.' + submodule_name - __import__(module_name) - module = sys.modules[module_name] - - if submodule_name not in OTHER_MODULE_DOCS: - find_names(module, names_dict) - - if submodule_name in args.module_names: - modules.append(module) - - dots = True - success = True - results = [] - - print(f"Running checks for {len(modules)} modules:") - - if args.doctests or not args.skip_examples: - init_matplotlib() - - for module in modules: - if dots: - if module is not modules[0]: - sys.stderr.write(' ') - sys.stderr.write(module.__name__ + ' ') - sys.stderr.flush() - - all_dict, deprecated, others = get_all_dict(module) - names = names_dict.get(module.__name__, set()) - - mod_results = [] - mod_results += check_items(all_dict, names, deprecated, others, module.__name__) - mod_results += check_rest(module, set(names).difference(deprecated), - dots=dots) - if args.doctests: - mod_results += check_doctests(module, (args.verbose >= 2), dots=dots, - doctest_warnings=args.doctest_warnings) - - for v in mod_results: - assert isinstance(v, tuple), v - - results.append((module, mod_results)) - - if dots: - sys.stderr.write("\n") - sys.stderr.flush() - - if not args.skip_examples: - examples_path = os.path.join( - os.getcwd(), 'doc', 'source', 'regression', '*.rst') - print(f'\nChecking examples files at {examples_path}:') - for filename in sorted(glob.glob(examples_path)): - if dots: - sys.stderr.write('\n') - sys.stderr.write(os.path.split(filename)[1] + ' ') - sys.stderr.flush() - - examples_results = check_doctests_testfile( - filename, (args.verbose >= 2), dots=dots, - doctest_warnings=args.doctest_warnings) - - def scratch(): pass # stub out a "module", see below - scratch.__name__ = filename - results.append((scratch, examples_results)) - - if dots: - sys.stderr.write("\n") - sys.stderr.flush() - - # Report results - all_success = True - - for module, mod_results in results: - success = all(x[1] for x in mod_results) - all_success = all_success and success - - if success and args.verbose == 0: - continue - - print("") - print("=" * len(module.__name__)) - print(module.__name__) - print("=" * len(module.__name__)) - print("") - - for name, success, output in mod_results: - if name is None: - if not success or args.verbose >= 1: - print(output.strip()) - print("") - elif not success or (args.verbose >= 2 and output.strip()): - print(name) - print("-"*len(name)) - print("") - print(output.strip()) - print("") - - if all_success: - print("\nOK: refguide and doctests checks passed!") - sys.exit(0) - else: - print("\nERROR: refguide or doctests have errors") - sys.exit(1) - - -if __name__ == '__main__': - main(argv=sys.argv[1:]) From 7854d507bceddf9223d5798fffc81387ead7eecf Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Tue, 25 Jun 2024 21:18:24 +0530 Subject: [PATCH 06/25] DOC: Fix failing documentation build --- .github/workflows/tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0ad1fd8f5..a3647094d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -132,10 +132,10 @@ jobs: # doctest docstrings pytest --doctest-modules --pyargs pywt -v --doctest-collect=api # Run Sphinx HTML docs builder, converting warnings to errors + # Move back out of demo/ to root directory cd .. - # XXX sphinx build is broken on CI - # pip install -r util/readthedocs/requirements.txt - # sphinx-build -b html -W --keep-going -d _build/doctrees . doc/source doc/build + pip install -r util/readthedocs/requirements.txt + sphinx-build -b html -W --keep-going -d _build/doctrees doc/source doc/build else pytest --pyargs pywt fi From b14cc9c83d5681e9247dc8e29378288a3c27f2fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Andr=C3=A9s=20Margffoy=20Tuay?= Date: Wed, 26 Jun 2024 05:15:01 -0500 Subject: [PATCH 07/25] CI: Add CI to test on free-threaded Python (#753) * CI: Add CI to test on free-threaded Python * FIX: Prevent strides and shape from going out of scope * BLD: change to using a generator for Cython, to make it easier to change flags for debugging purposes. Co-authored-by: Ralf Gommers --- .github/workflows/tests.yml | 35 +++++++++++++++++++++++++++++++++++ pywt/_extensions/_swt.pyx | 12 ++++++++++-- pywt/_extensions/meson.build | 10 +++++++++- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a3647094d..d860d9bfe 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -141,6 +141,41 @@ jobs: fi popd + test_pywavelets_linux_free_threaded: + name: linux-cp313t-with-scipy + runs-on: ubuntu-latest + strategy: + # Ensure that a wheel builder finishes even if another fails + fail-fast: false + + steps: + - name: Checkout PyWavelets + uses: actions/checkout@v4 + + # TODO: replace with setup-python when there is support + - uses: deadsnakes/action@6c8b9b82fe0b4344f4b98f2775fcc395df45e494 # v3.1.0 + with: + python-version: "3.13-dev" + nogil: true + + - name: Build package + run: | + which python + python --version + pip install --upgrade pip build + # We need nightly wheels for free-threaded support and latest fixes + pip install --pre -i https://pypi.anaconda.org/scientific-python-nightly-wheels/simple cython numpy scipy + pip install pytest meson-python ninja + pip install . -v --no-build-isolation + + - name: Run tests + env: + PYTHON_GIL: 0 + run: | + # Move out of source directory to avoid finding local pywt + cd demo + pytest --pyargs pywt + test_pywavelets_macos: name: macos-cp${{ matrix.python-version }}-${{ matrix.OPTIONS_NAME }} runs-on: macos-latest diff --git a/pywt/_extensions/_swt.pyx b/pywt/_extensions/_swt.pyx index 4b8b324eb..26e9e3349 100644 --- a/pywt/_extensions/_swt.pyx +++ b/pywt/_extensions/_swt.pyx @@ -165,6 +165,7 @@ cpdef swt_axis(np.ndarray data, Wavelet wavelet, size_t level, cdef common.ArrayInfo data_info, output_info cdef np.ndarray cD, cA cdef size_t[::1] output_shape + cdef np.npy_intp[::1] strides_view cdef size_t end_level = start_level + level cdef int retval = -5 cdef size_t i @@ -200,9 +201,16 @@ cpdef swt_axis(np.ndarray data, Wavelet wavelet, size_t level, for i in range(start_level+1, end_level+1): cA = np.empty(output_shape, dtype=data.dtype) cD = np.empty(output_shape, dtype=data.dtype) + # strides won't match data_info.strides if data is not C-contiguous - output_info.strides = cA.strides - output_info.shape = cA.shape + # We need an explicit copy of `cA.strides` here because cA is + # zero-initialized for complex dtypes further down in this same for-loop; + # the pointer to `cA.strides` would then be dangling (see gh-753). + strides_view = cA.strides + strides_view = strides_view.copy() + output_info.strides = &strides_view[0] + output_info.shape = &output_shape[0] + if data.dtype == np.float64: with nogil: retval = c_wt.double_downcoef_axis( diff --git a/pywt/_extensions/meson.build b/pywt/_extensions/meson.build index c6f02a414..09fa9aa79 100644 --- a/pywt/_extensions/meson.build +++ b/pywt/_extensions/meson.build @@ -82,6 +82,14 @@ libc_wt = static_library('c_wt', dependencies : py_dep, ) +cython_args = ['-3', '--fast-fail', '--output-file', '@OUTPUT@', '--include-dir', '@BUILD_ROOT@', '@INPUT@'] + +cython_gen = generator(cython, + arguments : cython_args, + output : '@BASENAME@.c', + depends : _cython_tree +) + pyx_files = [ ['_cwt', fs.copyfile('_cwt.pyx')], ['_dwt', fs.copyfile('_dwt.pyx')], @@ -92,7 +100,7 @@ pyx_files = [ cy_deps = declare_dependency(sources: [__init__py, _cython_tree])#, config_pxi]) foreach pyx_file: pyx_files py.extension_module(pyx_file[0], - pyx_file[1], + [cython_gen.process(pyx_file[1])], c_args : c_args, include_directories : 'c', dependencies : [np_dep, cy_deps], From 5d15c44eec1d3b12a309b7128ccaca85558cb695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Andr=C3=A9s=20Margffoy=20Tuay?= Date: Thu, 27 Jun 2024 18:03:07 -0500 Subject: [PATCH 08/25] CI: Add Linux nightly wheels for free-threaded Python 3.13 (#756) Also upgrade build from C99 to C17, because we need at least C99 to avoid errors in Cython-generated C code hitting a problem in CPython headers. Co-authored-by: Ralf Gommers --- .github/workflows/freethreaded_wheels.yml | 101 ++++++++++++++++++++++ meson.build | 2 +- 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/freethreaded_wheels.yml diff --git a/.github/workflows/freethreaded_wheels.yml b/.github/workflows/freethreaded_wheels.yml new file mode 100644 index 000000000..8cde14982 --- /dev/null +++ b/.github/workflows/freethreaded_wheels.yml @@ -0,0 +1,101 @@ +name: Build free-threaded wheels +on: + push: + tags: + - "v*" + - "buildwheels*" + branches: + # Runs on every merge to main to upload .dev0 wheels to anaconda.org + - main + - v1.** + # Make it possible to upload wheels manually if needed (for anaconda.org only, not PyPI) + workflow_dispatch: + inputs: + push_wheels: + description: > + Push wheels to Anaconda if "true". Default is "false". Warning: this will overwrite existing wheels. + required: false + default: "false" + # Upload wheels to anaconda.org on a schedule + schedule: + # Run at 0300 hours on days 3 and 17 of the month + - cron: "0 3 3,17 * *" +env: + CIBW_BUILD_VERBOSITY: 2 + CIBW_TEST_REQUIRES: pytest + CIBW_TEST_COMMAND: pytest --pyargs pywt -m "not slow" + CIBW_ENVIRONMENT: PIP_PREFER_BINARY=1 + +jobs: + build_linux_x86_64_free_threaded_wheels: + name: Build ${{ matrix.cibw_python }} ${{ matrix.cibw_arch }} ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + cibw_python: ["cp313t"] + cibw_arch: ["x86_64"] + steps: + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + with: + fetch-depth: 0 + - uses: actions/setup-python@v5 + name: Install Python + with: + python-version: "3.10" + - name: Setup environment variables + run: | + PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" + CIBW_DEPS="pip install --upgrade pip build &&\ + pip install --pre -i $PYPI_URL cython numpy scipy &&\ + pip install pytest meson-python ninja" + echo "CIBW_BEFORE_BUILD=$CIBW_DEPS" >> "$GITHUB_ENV" + echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" + echo "CIBW_TEST_COMMAND=PYTHON_GIL=0 $CIBW_TEST_COMMAND" >> "$GITHUB_ENV" + + - name: Build the wheel + uses: pypa/cibuildwheel@a8d190a111314a07eb5116036c4b3fb26a4e3162 # v2.19.0 + with: + output-dir: dist + env: + CIBW_BUILD: ${{ matrix.cibw_python }}-* + CIBW_ARCHS_LINUX: ${{ matrix.cibw_arch }} + CIBW_PRERELEASE_PYTHONS: True + CIBW_FREE_THREADED_SUPPORT: True + CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 + CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2 + CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation" + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + with: + name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} + path: ./dist/*.whl + if-no-files-found: error + + deploy_anaconda: + name: Release (Anaconda) + needs: [build_linux_x86_64_free_threaded_wheels] + # Run only on pushes to the main branch, on schedule, or when triggered manually + if: >- + github.repository == 'PyWavelets/pywt' && + (github.event_name == 'push' && github.ref == 'refs/heads/main') || + (github.event_name == 'workflow_dispatch' && github.event.inputs.push_wheels == 'true') || + (github.event_name == 'schedule') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + with: + fetch-depth: 0 + + - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + id: download + with: + pattern: "wheels_*" + path: dist/ + merge-multiple: true + + - name: Push to Anaconda PyPI index + uses: scientific-python/upload-nightly-action@b67d7fcc0396e1128a474d1ab2b48aa94680f9fc # v0.5.0 + with: + artifacts_path: dist/ + anaconda_nightly_upload_token: ${{ secrets.ANACONDA_ORG_UPLOAD_TOKEN }} diff --git a/meson.build b/meson.build index c4b9c9713..cce4725da 100644 --- a/meson.build +++ b/meson.build @@ -7,7 +7,7 @@ project( default_options: [ 'buildtype=debugoptimized', 'b_ndebug=if-release', - 'c_std=c99', + 'c_std=c17', ], ) From d3c51182659c1a2532df954198c2a77e0fd9647f Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 28 Jun 2024 01:05:12 +0200 Subject: [PATCH 09/25] BLD: bump aarch64 wheels to `musllinux_1_2` (matches numpy's config) --- .github/workflows/wheel_tests_and_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index fcef94f03..361c05073 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -88,7 +88,7 @@ jobs: CIBW_BUILD: ${{ matrix.cibw_python }}-* CIBW_ARCHS_LINUX: ${{ matrix.cibw_arch }} CIBW_MANYLINUX_AARCH64_IMAGE: manylinux2014 - CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_1 + CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_2 - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} From dbc066c5165f6254e65223f406ec98c22ee00f88 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 28 Jun 2024 01:10:06 +0200 Subject: [PATCH 10/25] CI: add macOS nightly wheels for free-threaded CPython Also bump the regular aarch64 wheel builds to `musllinux_1_2`; that's an inconsistency in config with numpy that is addressed here (noted because the Linux free-threaded wheels made that bump too). --- .github/workflows/freethreaded_wheels.yml | 74 ++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/.github/workflows/freethreaded_wheels.yml b/.github/workflows/freethreaded_wheels.yml index 8cde14982..c837dfd8c 100644 --- a/.github/workflows/freethreaded_wheels.yml +++ b/.github/workflows/freethreaded_wheels.yml @@ -44,7 +44,8 @@ jobs: name: Install Python with: python-version: "3.10" - - name: Setup environment variables + + - name: Install build deps; set CIBW environment variables run: | PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" CIBW_DEPS="pip install --upgrade pip build &&\ @@ -72,9 +73,78 @@ jobs: path: ./dist/*.whl if-no-files-found: error + build_macos_free_threaded_wheels: + name: Build ${{ matrix.cibw_python }} ${{ matrix.cibw_arch }} ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + # macos-13 is the last runner that supports Intel (x86_64) architecture + os: [macos-13, macos-14] + cibw_python: ["cp313t"] + cibw_arch: ["x86_64", "arm64"] + exclude: + - os: macos-14 + cibw_arch: "x86_64" + - os: macos-13 + cibw_arch: "arm64" + steps: + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + with: + fetch-depth: 0 + + - uses: actions/setup-python@v5 + name: Install Python + with: + python-version: "3.12" + + - name: Install build deps; set CIBW environment variables + run: | + PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" + CIBW_DEPS="pip install --upgrade pip build &&\ + pip install --pre -i $PYPI_URL cython numpy scipy &&\ + pip install pytest meson-python ninja" + echo "CIBW_BEFORE_BUILD=$CIBW_DEPS" >> "$GITHUB_ENV" + echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" + echo "CIBW_TEST_COMMAND=PYTHON_GIL=0 $CIBW_TEST_COMMAND" >> "$GITHUB_ENV" + + - name: Build wheels for CPython (macOS) (x86_64) + if: matrix.cibw_arch == 'x86_64' + uses: pypa/cibuildwheel@a8d190a111314a07eb5116036c4b3fb26a4e3162 # v2.19.0 + with: + output-dir: dist + env: + CIBW_BUILD: ${{ matrix.cibw_python }}-* + CIBW_ARCHS_MACOS: ${{ matrix.cibw_arch }} + CIBW_PRERELEASE_PYTHONS: True + CIBW_FREE_THREADED_SUPPORT: True + CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation" + + - name: Build wheels for CPython (macOS) (arm64) + if: matrix.cibw_arch == 'arm64' + uses: pypa/cibuildwheel@a8d190a111314a07eb5116036c4b3fb26a4e3162 # v2.19.0 + with: + output-dir: dist + env: + CIBW_BUILD: ${{ matrix.cibw_python }}-* + CIBW_ARCHS_MACOS: ${{ matrix.cibw_arch }} + CIBW_PRERELEASE_PYTHONS: True + CIBW_FREE_THREADED_SUPPORT: True + CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation" + + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + with: + name: wheels_macos_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} + path: ./dist/*.whl + if-no-files-found: error + deploy_anaconda: name: Release (Anaconda) - needs: [build_linux_x86_64_free_threaded_wheels] + needs: + [ + build_linux_x86_64_free_threaded_wheels, + build_macos_free_threaded_wheels, + ] # Run only on pushes to the main branch, on schedule, or when triggered manually if: >- github.repository == 'PyWavelets/pywt' && From 14c63ce24dcb9b871c7c2426ddafb9ab082f8f78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:48:51 +0000 Subject: [PATCH 11/25] Bump softprops/action-gh-release in the github-actions group Bumps the github-actions group with 1 update: [softprops/action-gh-release](/~https://github.com/softprops/action-gh-release). Updates `softprops/action-gh-release` from 2.0.5 to 2.0.6 - [Release notes](/~https://github.com/softprops/action-gh-release/releases) - [Changelog](/~https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](/~https://github.com/softprops/action-gh-release/compare/69320dbe05506a9a39fc8ae11030b214ec2d1f87...a74c6b72af54cfa997e81df42d94703d6313a2d0) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/wheel_tests_and_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index 361c05073..bdde9e26a 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -237,7 +237,7 @@ jobs: TWINE_PASSWORD: ${{ secrets.TWINE_TOKEN }} - name: Github release - uses: softprops/action-gh-release@69320dbe05506a9a39fc8ae11030b214ec2d1f87 # v2.0.5 + uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0 # v2.0.6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} From 4bb4a292b2782e064390b38716dba665c440cb2d Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 16 Jul 2024 11:04:57 +0200 Subject: [PATCH 12/25] BLD: mark extension modules as compatible to run without the GIL This leaves the `PYTHON_GIL=0` in the CI config for now, because tests depend on scipy/matplotlib which haven't marked their extension modules as compatible. --- pywt/_extensions/meson.build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pywt/_extensions/meson.build b/pywt/_extensions/meson.build index 09fa9aa79..8ebf71ea2 100644 --- a/pywt/_extensions/meson.build +++ b/pywt/_extensions/meson.build @@ -82,7 +82,11 @@ libc_wt = static_library('c_wt', dependencies : py_dep, ) +cy = meson.get_compiler('cython') cython_args = ['-3', '--fast-fail', '--output-file', '@OUTPUT@', '--include-dir', '@BUILD_ROOT@', '@INPUT@'] +if cy.version().version_compare('>=3.1.0') + cython_args += ['-Xfreethreading_compatible=True'] +endif cython_gen = generator(cython, arguments : cython_args, From 4356fe06427ebec8eec7dd0ea9d2a6ff659c46a1 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Sat, 27 Jul 2024 15:38:18 +0200 Subject: [PATCH 13/25] BLD: fix a few install tags for generated .py files --- pywt/meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pywt/meson.build b/pywt/meson.build index 5d6eeec19..8c66156f9 100644 --- a/pywt/meson.build +++ b/pywt/meson.build @@ -30,6 +30,7 @@ generate_version = custom_target( input: '../util/version_utils.py', command: [py, '@INPUT@', '--source-root', '@SOURCE_ROOT@'], install_dir: py.get_install_dir() / 'pywt', + install_tag: 'python-runtime', ) cc = meson.get_compiler('c') @@ -51,7 +52,8 @@ _c99_config = configure_file( output: '_c99_config.py', configuration: cdata, install: true, - install_dir: py.get_install_dir() / 'pywt' + install_dir: py.get_install_dir() / 'pywt', + install_tag: 'python-runtime', ) install_subdir('data', install_dir: py.get_install_dir() / 'pywt') From 105cc91a9d4ceb44fd63ee4d421c158aac3198bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 14:26:41 +0000 Subject: [PATCH 14/25] Bump the github-actions group with 4 updates Bumps the github-actions group with 4 updates: [pypa/cibuildwheel](/~https://github.com/pypa/cibuildwheel), [actions/upload-artifact](/~https://github.com/actions/upload-artifact), [actions/download-artifact](/~https://github.com/actions/download-artifact) and [softprops/action-gh-release](/~https://github.com/softprops/action-gh-release). Updates `pypa/cibuildwheel` from 2.18.1 to 2.19.2 - [Release notes](/~https://github.com/pypa/cibuildwheel/releases) - [Commits](/~https://github.com/pypa/cibuildwheel/compare/v2.18.1...v2.19.2) Updates `actions/upload-artifact` from 4.3.3 to 4.3.4 - [Release notes](/~https://github.com/actions/upload-artifact/releases) - [Commits](/~https://github.com/actions/upload-artifact/compare/65462800fd760344b1a7b4382951275a0abb4808...0b2256b8c012f0828dc542b3febcab082c67f72b) Updates `actions/download-artifact` from 4.1.7 to 4.1.8 - [Release notes](/~https://github.com/actions/download-artifact/releases) - [Commits](/~https://github.com/actions/download-artifact/compare/65a9edc5881444af0b9093a5e628f2fe47ea3b2e...fa0a91b85d4f404e444e00e005971372dc801d16) Updates `softprops/action-gh-release` from 2.0.6 to 2.0.8 - [Release notes](/~https://github.com/softprops/action-gh-release/releases) - [Changelog](/~https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](/~https://github.com/softprops/action-gh-release/compare/a74c6b72af54cfa997e81df42d94703d6313a2d0...c062e08bd532815e2082a85e87e3ef29c3e6d191) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/download-artifact dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: softprops/action-gh-release dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/emscripten.yml | 2 +- .github/workflows/freethreaded_wheels.yml | 12 +++++----- .github/workflows/wheel_tests_and_release.yml | 24 +++++++++---------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 540c50462..aaeae2e70 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v4 - name: Build and test PyWavelets - uses: pypa/cibuildwheel@v2.19.1 + uses: pypa/cibuildwheel@v2.19.2 env: CIBW_PLATFORM: pyodide CIBW_TEST_REQUIRES: pytest matplotlib diff --git a/.github/workflows/freethreaded_wheels.yml b/.github/workflows/freethreaded_wheels.yml index c837dfd8c..c0f289dc8 100644 --- a/.github/workflows/freethreaded_wheels.yml +++ b/.github/workflows/freethreaded_wheels.yml @@ -56,7 +56,7 @@ jobs: echo "CIBW_TEST_COMMAND=PYTHON_GIL=0 $CIBW_TEST_COMMAND" >> "$GITHUB_ENV" - name: Build the wheel - uses: pypa/cibuildwheel@a8d190a111314a07eb5116036c4b3fb26a4e3162 # v2.19.0 + uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # v2.19.0 with: output-dir: dist env: @@ -67,7 +67,7 @@ jobs: CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2 CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation" - - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -110,7 +110,7 @@ jobs: - name: Build wheels for CPython (macOS) (x86_64) if: matrix.cibw_arch == 'x86_64' - uses: pypa/cibuildwheel@a8d190a111314a07eb5116036c4b3fb26a4e3162 # v2.19.0 + uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # v2.19.0 with: output-dir: dist env: @@ -122,7 +122,7 @@ jobs: - name: Build wheels for CPython (macOS) (arm64) if: matrix.cibw_arch == 'arm64' - uses: pypa/cibuildwheel@a8d190a111314a07eb5116036c4b3fb26a4e3162 # v2.19.0 + uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # v2.19.0 with: output-dir: dist env: @@ -132,7 +132,7 @@ jobs: CIBW_FREE_THREADED_SUPPORT: True CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation" - - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: wheels_macos_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -157,7 +157,7 @@ jobs: with: fetch-depth: 0 - - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 id: download with: pattern: "wheels_*" diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index bdde9e26a..cb86f02e7 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -45,7 +45,7 @@ jobs: with: python-version: "3.10" - name: Build the wheel - uses: pypa/cibuildwheel@ba8be0d98853f5744f24e7f902c8adef7ae2e7f3 # 2.18.1 + uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # 2.18.1 with: output-dir: dist env: @@ -53,7 +53,7 @@ jobs: CIBW_ARCHS_LINUX: ${{ matrix.cibw_arch }} CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_1 - - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -81,7 +81,7 @@ jobs: with: platforms: arm64 - name: Build the wheel - uses: pypa/cibuildwheel@ba8be0d98853f5744f24e7f902c8adef7ae2e7f3 # 2.18.1 + uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # 2.18.1 with: output-dir: dist env: @@ -89,7 +89,7 @@ jobs: CIBW_ARCHS_LINUX: ${{ matrix.cibw_arch }} CIBW_MANYLINUX_AARCH64_IMAGE: manylinux2014 CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_2 - - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -121,7 +121,7 @@ jobs: - name: Build wheels for CPython (macOS) (x86_64) if: matrix.cibw_arch == 'x86_64' - uses: pypa/cibuildwheel@ba8be0d98853f5744f24e7f902c8adef7ae2e7f3 # 2.18.1 + uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # 2.18.1 with: output-dir: dist env: @@ -130,14 +130,14 @@ jobs: - name: Build wheels for CPython (macOS) (arm64) if: matrix.cibw_arch == 'arm64' - uses: pypa/cibuildwheel@ba8be0d98853f5744f24e7f902c8adef7ae2e7f3 # 2.18.1 + uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # 2.18.1 with: output-dir: dist env: CIBW_BUILD: ${{ matrix.cibw_python }}-* CIBW_ARCHS_MACOS: ${{ matrix.cibw_arch }} - - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: wheels_macos_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -175,14 +175,14 @@ jobs: architecture: x64 - name: Build Windows wheels for CPython - uses: pypa/cibuildwheel@ba8be0d98853f5744f24e7f902c8adef7ae2e7f3 # 2.18.1 + uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # 2.18.1 with: output-dir: dist env: CIBW_BUILD: ${{ matrix.cibw_python }}-* CIBW_ARCHS_WINDOWS: ${{ matrix.cibw_arch }} - - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: wheels_windows_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -216,7 +216,7 @@ jobs: pip install twine pip install cython numpy build - - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 id: download with: pattern: "wheels_*" @@ -237,7 +237,7 @@ jobs: TWINE_PASSWORD: ${{ secrets.TWINE_TOKEN }} - name: Github release - uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0 # v2.0.6 + uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} @@ -263,7 +263,7 @@ jobs: with: fetch-depth: 0 - - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 id: download with: pattern: "wheels_*" From 2dafd36278f8e13787bfd093ceda68f8b31c50cd Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 1 Aug 2024 17:48:06 +0200 Subject: [PATCH 15/25] CI: use cibuildwheel v2.19.2 (the actual commit from the tag) --- .github/workflows/emscripten.yml | 2 +- .github/workflows/freethreaded_wheels.yml | 6 +++--- .github/workflows/wheel_tests_and_release.yml | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index aaeae2e70..9b5472e07 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v4 - name: Build and test PyWavelets - uses: pypa/cibuildwheel@v2.19.2 + uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 env: CIBW_PLATFORM: pyodide CIBW_TEST_REQUIRES: pytest matplotlib diff --git a/.github/workflows/freethreaded_wheels.yml b/.github/workflows/freethreaded_wheels.yml index c0f289dc8..af960f256 100644 --- a/.github/workflows/freethreaded_wheels.yml +++ b/.github/workflows/freethreaded_wheels.yml @@ -56,7 +56,7 @@ jobs: echo "CIBW_TEST_COMMAND=PYTHON_GIL=0 $CIBW_TEST_COMMAND" >> "$GITHUB_ENV" - name: Build the wheel - uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # v2.19.0 + uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 with: output-dir: dist env: @@ -110,7 +110,7 @@ jobs: - name: Build wheels for CPython (macOS) (x86_64) if: matrix.cibw_arch == 'x86_64' - uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # v2.19.0 + uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 with: output-dir: dist env: @@ -122,7 +122,7 @@ jobs: - name: Build wheels for CPython (macOS) (arm64) if: matrix.cibw_arch == 'arm64' - uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # v2.19.0 + uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 with: output-dir: dist env: diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index cb86f02e7..83645300c 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -45,7 +45,7 @@ jobs: with: python-version: "3.10" - name: Build the wheel - uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # 2.18.1 + uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 with: output-dir: dist env: @@ -81,7 +81,7 @@ jobs: with: platforms: arm64 - name: Build the wheel - uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # 2.18.1 + uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 with: output-dir: dist env: @@ -121,7 +121,7 @@ jobs: - name: Build wheels for CPython (macOS) (x86_64) if: matrix.cibw_arch == 'x86_64' - uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # 2.18.1 + uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 with: output-dir: dist env: @@ -130,7 +130,7 @@ jobs: - name: Build wheels for CPython (macOS) (arm64) if: matrix.cibw_arch == 'arm64' - uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # 2.18.1 + uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 with: output-dir: dist env: @@ -175,7 +175,7 @@ jobs: architecture: x64 - name: Build Windows wheels for CPython - uses: pypa/cibuildwheel@147de6f4f7bba00e694321b7cf3a519441a444fa # 2.18.1 + uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 with: output-dir: dist env: From 9d8e15aaf03fcbe21648b173e672eb35c0f852e2 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Sat, 27 Jul 2024 16:45:29 +0200 Subject: [PATCH 16/25] BLD/CI: support Python 3.13 (cp313/cp313t) in pyproject.toml and wheel builds This is a single large update that does the following: - Depend on numpy>=2.1.0rc1 for Python 3.13 - Update to `cibuildwheel` 2.20.0 (for Python 3.13.0rc1) - Update `musllinux_2014` from `1_1` to `1_2` (`1_1 is almost EOL, and little-used) - Merge the free-threaded and regular wheel build jobs - Drop `PYTHON_GIL=0` from testing, because we don't need it anymore (all extension modules in PyWavelets and NumPy are marked as compatible) - Build cp313 and cp313t wheels in release jobs - Add macOS arm64 free-threaded wheels --- .github/workflows/emscripten.yml | 2 +- .github/workflows/freethreaded_wheels.yml | 171 ------------------ .github/workflows/wheel_tests_and_release.yml | 59 +++++- pyproject.toml | 3 +- 4 files changed, 52 insertions(+), 183 deletions(-) delete mode 100644 .github/workflows/freethreaded_wheels.yml diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 9b5472e07..d6c44b1c9 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v4 - name: Build and test PyWavelets - uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 + uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 env: CIBW_PLATFORM: pyodide CIBW_TEST_REQUIRES: pytest matplotlib diff --git a/.github/workflows/freethreaded_wheels.yml b/.github/workflows/freethreaded_wheels.yml deleted file mode 100644 index af960f256..000000000 --- a/.github/workflows/freethreaded_wheels.yml +++ /dev/null @@ -1,171 +0,0 @@ -name: Build free-threaded wheels -on: - push: - tags: - - "v*" - - "buildwheels*" - branches: - # Runs on every merge to main to upload .dev0 wheels to anaconda.org - - main - - v1.** - # Make it possible to upload wheels manually if needed (for anaconda.org only, not PyPI) - workflow_dispatch: - inputs: - push_wheels: - description: > - Push wheels to Anaconda if "true". Default is "false". Warning: this will overwrite existing wheels. - required: false - default: "false" - # Upload wheels to anaconda.org on a schedule - schedule: - # Run at 0300 hours on days 3 and 17 of the month - - cron: "0 3 3,17 * *" -env: - CIBW_BUILD_VERBOSITY: 2 - CIBW_TEST_REQUIRES: pytest - CIBW_TEST_COMMAND: pytest --pyargs pywt -m "not slow" - CIBW_ENVIRONMENT: PIP_PREFER_BINARY=1 - -jobs: - build_linux_x86_64_free_threaded_wheels: - name: Build ${{ matrix.cibw_python }} ${{ matrix.cibw_arch }} ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - cibw_python: ["cp313t"] - cibw_arch: ["x86_64"] - steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - with: - fetch-depth: 0 - - uses: actions/setup-python@v5 - name: Install Python - with: - python-version: "3.10" - - - name: Install build deps; set CIBW environment variables - run: | - PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" - CIBW_DEPS="pip install --upgrade pip build &&\ - pip install --pre -i $PYPI_URL cython numpy scipy &&\ - pip install pytest meson-python ninja" - echo "CIBW_BEFORE_BUILD=$CIBW_DEPS" >> "$GITHUB_ENV" - echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" - echo "CIBW_TEST_COMMAND=PYTHON_GIL=0 $CIBW_TEST_COMMAND" >> "$GITHUB_ENV" - - - name: Build the wheel - uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 - with: - output-dir: dist - env: - CIBW_BUILD: ${{ matrix.cibw_python }}-* - CIBW_ARCHS_LINUX: ${{ matrix.cibw_arch }} - CIBW_PRERELEASE_PYTHONS: True - CIBW_FREE_THREADED_SUPPORT: True - CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 - CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2 - CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation" - - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 - with: - name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} - path: ./dist/*.whl - if-no-files-found: error - - build_macos_free_threaded_wheels: - name: Build ${{ matrix.cibw_python }} ${{ matrix.cibw_arch }} ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - # macos-13 is the last runner that supports Intel (x86_64) architecture - os: [macos-13, macos-14] - cibw_python: ["cp313t"] - cibw_arch: ["x86_64", "arm64"] - exclude: - - os: macos-14 - cibw_arch: "x86_64" - - os: macos-13 - cibw_arch: "arm64" - steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - with: - fetch-depth: 0 - - - uses: actions/setup-python@v5 - name: Install Python - with: - python-version: "3.12" - - - name: Install build deps; set CIBW environment variables - run: | - PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" - CIBW_DEPS="pip install --upgrade pip build &&\ - pip install --pre -i $PYPI_URL cython numpy scipy &&\ - pip install pytest meson-python ninja" - echo "CIBW_BEFORE_BUILD=$CIBW_DEPS" >> "$GITHUB_ENV" - echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" - echo "CIBW_TEST_COMMAND=PYTHON_GIL=0 $CIBW_TEST_COMMAND" >> "$GITHUB_ENV" - - - name: Build wheels for CPython (macOS) (x86_64) - if: matrix.cibw_arch == 'x86_64' - uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 - with: - output-dir: dist - env: - CIBW_BUILD: ${{ matrix.cibw_python }}-* - CIBW_ARCHS_MACOS: ${{ matrix.cibw_arch }} - CIBW_PRERELEASE_PYTHONS: True - CIBW_FREE_THREADED_SUPPORT: True - CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation" - - - name: Build wheels for CPython (macOS) (arm64) - if: matrix.cibw_arch == 'arm64' - uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 - with: - output-dir: dist - env: - CIBW_BUILD: ${{ matrix.cibw_python }}-* - CIBW_ARCHS_MACOS: ${{ matrix.cibw_arch }} - CIBW_PRERELEASE_PYTHONS: True - CIBW_FREE_THREADED_SUPPORT: True - CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation" - - - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 - with: - name: wheels_macos_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} - path: ./dist/*.whl - if-no-files-found: error - - deploy_anaconda: - name: Release (Anaconda) - needs: - [ - build_linux_x86_64_free_threaded_wheels, - build_macos_free_threaded_wheels, - ] - # Run only on pushes to the main branch, on schedule, or when triggered manually - if: >- - github.repository == 'PyWavelets/pywt' && - (github.event_name == 'push' && github.ref == 'refs/heads/main') || - (github.event_name == 'workflow_dispatch' && github.event.inputs.push_wheels == 'true') || - (github.event_name == 'schedule') - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - with: - fetch-depth: 0 - - - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - id: download - with: - pattern: "wheels_*" - path: dist/ - merge-multiple: true - - - name: Push to Anaconda PyPI index - uses: scientific-python/upload-nightly-action@b67d7fcc0396e1128a474d1ab2b48aa94680f9fc # v0.5.0 - with: - artifacts_path: dist/ - anaconda_nightly_upload_token: ${{ secrets.ANACONDA_ORG_UPLOAD_TOKEN }} diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index 83645300c..97e342b23 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -34,7 +34,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - cibw_python: ["cp310", "cp311", "cp312"] + cibw_python: ["cp310", "cp311", "cp312", "cp313", "cp313t"] cibw_arch: ["x86_64"] steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 @@ -44,15 +44,29 @@ jobs: name: Install Python with: python-version: "3.10" + + - name: Install build deps; set CIBW environment variables + if: ${{ matrix.cibw_python }} == "cp313" || ${{ matrix.cibw_python }} == "cp313t" + run: | + PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" + CIBW_DEPS="pip install --upgrade pip build &&\ + pip install --pre -i $PYPI_URL cython numpy scipy &&\ + pip install pytest meson-python ninja" + NO_BUILD_ISOLATION="pip; args: --no-build-isolation" + echo "CIBW_BEFORE_BUILD=$CIBW_DEPS" >> "$GITHUB_ENV" + echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" + echo "CIBW_BUILD_FRONTEND=$NO_BUILD_ISOLATION" >> "$GITHUB_ENV" + - name: Build the wheel - uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 + uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 with: output-dir: dist env: CIBW_BUILD: ${{ matrix.cibw_python }}-* CIBW_ARCHS_LINUX: ${{ matrix.cibw_arch }} CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 - CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_1 + CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2 + CIBW_FREE_THREADED_SUPPORT: True - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} @@ -66,7 +80,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - cibw_python: ["cp310", "cp311", "cp312"] + cibw_python: ["cp310", "cp311", "cp312", "cp313"] cibw_arch: ["aarch64"] steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 @@ -80,8 +94,17 @@ jobs: uses: docker/setup-qemu-action@v3 with: platforms: arm64 + + - name: Install test dep; set CIBW environment variables + # Can be removed once numpy 2.1.0 is released + if: ${{ matrix.cibw_python }} == "cp313" + run: | + PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" + CIBW_DEPS="pip install --pre -i $PYPI_URL numpy" + echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" + - name: Build the wheel - uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 + uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 with: output-dir: dist env: @@ -102,13 +125,16 @@ jobs: matrix: # macos-13 is the last runner that supports Intel (x86_64) architecture os: [macos-13, macos-14] - cibw_python: ["cp310", "cp311", "cp312"] + cibw_python: ["cp310", "cp311", "cp312", "cp313", "cp313t"] cibw_arch: ["x86_64", "arm64"] exclude: - os: macos-14 cibw_arch: "x86_64" - os: macos-13 cibw_arch: "arm64" + - os: macos-13 + cibw_arch: "x86_64" + cibw_python: "cp313t" steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: @@ -119,9 +145,21 @@ jobs: with: python-version: "3.12" + - name: Install build deps; set CIBW environment variables + if: ${{ matrix.cibw_python }} == "cp313" || ${{ matrix.cibw_python }} == "cp313t" + run: | + PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" + CIBW_DEPS="pip install --upgrade pip build &&\ + pip install --pre -i $PYPI_URL cython numpy scipy &&\ + pip install pytest meson-python ninja" + NO_BUILD_ISOLATION="pip; args: --no-build-isolation" + echo "CIBW_BEFORE_BUILD=$CIBW_DEPS" >> "$GITHUB_ENV" + echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" + echo "CIBW_BUILD_FRONTEND=$NO_BUILD_ISOLATION" >> "$GITHUB_ENV" + - name: Build wheels for CPython (macOS) (x86_64) if: matrix.cibw_arch == 'x86_64' - uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 + uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 with: output-dir: dist env: @@ -130,12 +168,13 @@ jobs: - name: Build wheels for CPython (macOS) (arm64) if: matrix.cibw_arch == 'arm64' - uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 + uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 with: output-dir: dist env: CIBW_BUILD: ${{ matrix.cibw_python }}-* CIBW_ARCHS_MACOS: ${{ matrix.cibw_arch }} + CIBW_FREE_THREADED_SUPPORT: True - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: @@ -151,7 +190,7 @@ jobs: matrix: os: [windows-latest] cibw_arch: ["AMD64", "x86"] - cibw_python: ["cp310", "cp311", "cp312"] + cibw_python: ["cp310", "cp311", "cp312", "cp313"] steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: @@ -175,7 +214,7 @@ jobs: architecture: x64 - name: Build Windows wheels for CPython - uses: pypa/cibuildwheel@7e5a838a63ac8128d71ab2dfd99e4634dd1bca09 # v2.19.2 + uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 with: output-dir: dist env: diff --git a/pyproject.toml b/pyproject.toml index f799ae1dd..ff99f7ee8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,8 @@ requires = [ # Note that building against numpy 1.x works fine too - users and # redistributors can do this by installing the numpy version they like and # disabling build isolation. - "numpy>=2.0.0b1", + "numpy>=2.0.0; python_version<'3.13'", + "numpy>=2.1.0.rc1; python_version>='3.13'", ] [project] From 96dfb3305cc46c0599ef33b8f1a153f9579470bd Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 12 Aug 2024 17:56:51 +0200 Subject: [PATCH 17/25] DOC: add release notes for 1.7.0 --- doc/release/1.7.0-notes.rst | 62 ++++++++++++++++++++++++++++++++++++ doc/source/release.1.7.0.rst | 1 + doc/source/releasenotes.rst | 1 + pyproject.toml | 1 + 4 files changed, 65 insertions(+) create mode 100644 doc/release/1.7.0-notes.rst create mode 100644 doc/source/release.1.7.0.rst diff --git a/doc/release/1.7.0-notes.rst b/doc/release/1.7.0-notes.rst new file mode 100644 index 000000000..ac3b8ff58 --- /dev/null +++ b/doc/release/1.7.0-notes.rst @@ -0,0 +1,62 @@ +============================== +PyWavelets 1.7.0 Release Notes +============================== + +We are very pleased to announce the release of PyWavelets 1.7.0. This release +is a minor update to 1.6.x. It adds support for Python 3.13, including for +free-threaded CPython. The supported NumPy and Cython versions are unchanged +from 1.6.x. + +Note that building from source with free-threaded CPython requires a recent +development version of Cython (>=3.1.0a0). + +Other noteworthy improvements: + +- Most examples in the documentation are now interactive, powered by + JupyterLite and Pyodide. +- The ``musllinux`` wheels were upgraded from ``musllinux_1_1`` to + ``musllinux_1_2`` (for both x86-64 and aarch64). + + +Authors +======= + +* Evgeni Burovski + +* Ralf Gommers +* Agriya Khetarpal +* Jarrod Millman +* Edgar Andrés Margffoy Tuay + + +A total of 5 people contributed to this release. +People with a "+" by their names contributed a patch for the first time. +This list of names is automatically generated, and may not be fully complete. + + +Issues closed for v1.7.0 +------------------------ + +* `#742 `__: Start building WASM wheels against newer Pyodide (version 0.26.0) + + +Pull requests for v1.7.0 +------------------------ + +* `#702 `__: BLD: Test editable installations for PyWavelets in CI +* `#722 `__: Drop support for older dependencies (see SPEC 0) +* `#726 `__: MAINT: set version to 1.7.0.dev0 +* `#734 `__: DOC: Fix incorrect indentations for a few interactive examples +* `#737 `__: DOC, DEP: Remove custom \`:button_text\` directive option, bump... +* `#739 `__: DEP: Remove \`docutils\` upper-pin, bump \`sphinx\` +* `#743 `__: FIX, CI: Temporarily disable \`pytest\`'s caching in Pyodide... +* `#744 `__: CI, BLD: Use \`cibuildwheel\` to build and test Pyodide/WASM... +* `#745 `__: Bump the github-actions group with 2 updates +* `#747 `__: Use \`scipy-doctest\` instead of \`refguide-check\` +* `#748 `__: DOC: easy_install is no longer a thing +* `#753 `__: CI: Add CI to test on free-threaded Python +* `#756 `__: CI: Add CI to release nightly wheels against free-threaded Python... +* `#757 `__: CI: add macOS nightly wheels for free-threaded CPython +* `#759 `__: Bump softprops/action-gh-release from 2.0.5 to 2.0.6 in the github-actions... +* `#761 `__: BLD: mark extension modules as compatible to run without the... +* `#762 `__: BLD: fix a few install tags for generated .py files +* `#763 `__: Bump the github-actions group with 4 updates +* `#764 `__: BLD/CI: support Python 3.13 (cp313/cp313t) in pyproject.toml... diff --git a/doc/source/release.1.7.0.rst b/doc/source/release.1.7.0.rst new file mode 100644 index 000000000..49c2b1285 --- /dev/null +++ b/doc/source/release.1.7.0.rst @@ -0,0 +1 @@ +.. include:: ../release/1.7.0-notes.rst diff --git a/doc/source/releasenotes.rst b/doc/source/releasenotes.rst index 6b48cef79..56cfec825 100644 --- a/doc/source/releasenotes.rst +++ b/doc/source/releasenotes.rst @@ -4,6 +4,7 @@ Release Notes .. toctree:: :maxdepth: 1 + release.1.7.0 release.1.6.0 release.1.5.0 release.1.4.1 diff --git a/pyproject.toml b/pyproject.toml index ff99f7ee8..6109b33a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Libraries :: Python Modules" ] From f7a27f9b69f352336165e06a084cc21e564e3b86 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 12 Aug 2024 17:57:53 +0200 Subject: [PATCH 18/25] REL: set version to 1.7.0 --- meson.build | 2 +- pyproject.toml | 2 +- util/version_utils.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index cce4725da..63c12d223 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'PyWavelets', 'c', 'cython', - version: '1.7.0.dev0', + version: '1.7.0', license: 'MIT', meson_version: '>= 1.1.0', default_options: [ diff --git a/pyproject.toml b/pyproject.toml index 6109b33a5..eb6a5f357 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ requires = [ [project] name = "PyWavelets" -version = "1.7.0.dev0" +version = "1.7.0" # TODO: add `license-files` once PEP 639 is accepted (see meson-python#88) # at that point, no longer include them in `py3.install_sources()` license = {file = "LICENSE"} diff --git a/util/version_utils.py b/util/version_utils.py index 3cad9b86b..75a643e64 100644 --- a/util/version_utils.py +++ b/util/version_utils.py @@ -5,7 +5,7 @@ MAJOR = 1 MINOR = 7 MICRO = 0 -ISRELEASED = False +ISRELEASED = True VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO) From 43a662c40594f0739471286ece033f2e758e291b Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 12 Aug 2024 18:00:19 +0200 Subject: [PATCH 19/25] REL: set version to 1.8.0.dev0 --- meson.build | 2 +- pyproject.toml | 2 +- util/version_utils.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 63c12d223..1010af3de 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'PyWavelets', 'c', 'cython', - version: '1.7.0', + version: '1.8.0.dev0', license: 'MIT', meson_version: '>= 1.1.0', default_options: [ diff --git a/pyproject.toml b/pyproject.toml index eb6a5f357..4326ffa9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ requires = [ [project] name = "PyWavelets" -version = "1.7.0" +version = "1.8.0.dev0" # TODO: add `license-files` once PEP 639 is accepted (see meson-python#88) # at that point, no longer include them in `py3.install_sources()` license = {file = "LICENSE"} diff --git a/util/version_utils.py b/util/version_utils.py index 75a643e64..ef6f45075 100644 --- a/util/version_utils.py +++ b/util/version_utils.py @@ -3,9 +3,9 @@ import subprocess MAJOR = 1 -MINOR = 7 +MINOR = 8 MICRO = 0 -ISRELEASED = True +ISRELEASED = False VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO) From 2d44c97d0634acafc0d5734def0f00e8d7893abe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 12:46:13 +0200 Subject: [PATCH 20/25] Bump actions/upload-artifact in the github-actions group (#766) Bumps the github-actions group with 1 update: [actions/upload-artifact](/~https://github.com/actions/upload-artifact). Updates `actions/upload-artifact` from 4.3.4 to 4.4.0 - [Release notes](/~https://github.com/actions/upload-artifact/releases) - [Commits](/~https://github.com/actions/upload-artifact/compare/0b2256b8c012f0828dc542b3febcab082c67f72b...50769540e7f4bd5e21e526ee35c689e35e0d6874) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wheel_tests_and_release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index 97e342b23..93c7cd625 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -67,7 +67,7 @@ jobs: CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2 CIBW_FREE_THREADED_SUPPORT: True - - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -112,7 +112,7 @@ jobs: CIBW_ARCHS_LINUX: ${{ matrix.cibw_arch }} CIBW_MANYLINUX_AARCH64_IMAGE: manylinux2014 CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_2 - - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -176,7 +176,7 @@ jobs: CIBW_ARCHS_MACOS: ${{ matrix.cibw_arch }} CIBW_FREE_THREADED_SUPPORT: True - - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: wheels_macos_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -221,7 +221,7 @@ jobs: CIBW_BUILD: ${{ matrix.cibw_python }}-* CIBW_ARCHS_WINDOWS: ${{ matrix.cibw_arch }} - - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: wheels_windows_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl From ba7a9e969e6f4e44a4552c2f573de952e1af2bdf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 07:59:33 +0200 Subject: [PATCH 21/25] Bump the github-actions group with 3 updates (#770) Bumps the github-actions group with 3 updates: [pypa/cibuildwheel](/~https://github.com/pypa/cibuildwheel), [scientific-python/upload-nightly-action](/~https://github.com/scientific-python/upload-nightly-action) and [deadsnakes/action](/~https://github.com/deadsnakes/action). Updates `pypa/cibuildwheel` from 2.20.0 to 2.21.1 - [Release notes](/~https://github.com/pypa/cibuildwheel/releases) - [Changelog](/~https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](/~https://github.com/pypa/cibuildwheel/compare/bd033a44476646b606efccdd5eed92d5ea1d77ad...d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23) Updates `scientific-python/upload-nightly-action` from 0.5.0 to 0.6.1 - [Release notes](/~https://github.com/scientific-python/upload-nightly-action/releases) - [Commits](/~https://github.com/scientific-python/upload-nightly-action/compare/b67d7fcc0396e1128a474d1ab2b48aa94680f9fc...82396a2ed4269ba06c6b2988bb4fd568ef3c3d6b) Updates `deadsnakes/action` from 3.1.0 to 3.2.0 - [Release notes](/~https://github.com/deadsnakes/action/releases) - [Commits](/~https://github.com/deadsnakes/action/compare/6c8b9b82fe0b4344f4b98f2775fcc395df45e494...e640ac8743173a67cca4d7d77cd837e514bf98e8) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: scientific-python/upload-nightly-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: deadsnakes/action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/emscripten.yml | 4 ++-- .github/workflows/tests.yml | 2 +- .github/workflows/wheel_tests_and_release.yml | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index d6c44b1c9..242988201 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v4 - name: Build and test PyWavelets - uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 + uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 env: CIBW_PLATFORM: pyodide CIBW_TEST_REQUIRES: pytest matplotlib @@ -51,7 +51,7 @@ jobs: (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_wheels == 'true') || (github.event_name == 'schedule') - uses: scientific-python/upload-nightly-action@b67d7fcc0396e1128a474d1ab2b48aa94680f9fc # v0.5.0 + uses: scientific-python/upload-nightly-action@82396a2ed4269ba06c6b2988bb4fd568ef3c3d6b # v0.6.1 with: artifacts_path: wheelhouse/ anaconda_nightly_upload_token: ${{ secrets.ANACONDA_ORG_UPLOAD_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d860d9bfe..85e639948 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -153,7 +153,7 @@ jobs: uses: actions/checkout@v4 # TODO: replace with setup-python when there is support - - uses: deadsnakes/action@6c8b9b82fe0b4344f4b98f2775fcc395df45e494 # v3.1.0 + - uses: deadsnakes/action@e640ac8743173a67cca4d7d77cd837e514bf98e8 # v3.2.0 with: python-version: "3.13-dev" nogil: true diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index 93c7cd625..8227a29b0 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -58,7 +58,7 @@ jobs: echo "CIBW_BUILD_FRONTEND=$NO_BUILD_ISOLATION" >> "$GITHUB_ENV" - name: Build the wheel - uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 + uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 with: output-dir: dist env: @@ -104,7 +104,7 @@ jobs: echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" - name: Build the wheel - uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 + uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 with: output-dir: dist env: @@ -159,7 +159,7 @@ jobs: - name: Build wheels for CPython (macOS) (x86_64) if: matrix.cibw_arch == 'x86_64' - uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 + uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 with: output-dir: dist env: @@ -168,7 +168,7 @@ jobs: - name: Build wheels for CPython (macOS) (arm64) if: matrix.cibw_arch == 'arm64' - uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 + uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 with: output-dir: dist env: @@ -214,7 +214,7 @@ jobs: architecture: x64 - name: Build Windows wheels for CPython - uses: pypa/cibuildwheel@bd033a44476646b606efccdd5eed92d5ea1d77ad # v2.20.0 + uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 with: output-dir: dist env: @@ -310,7 +310,7 @@ jobs: merge-multiple: true - name: Push to Anaconda PyPI index - uses: scientific-python/upload-nightly-action@b67d7fcc0396e1128a474d1ab2b48aa94680f9fc # v0.5.0 + uses: scientific-python/upload-nightly-action@82396a2ed4269ba06c6b2988bb4fd568ef3c3d6b # v0.6.1 with: artifacts_path: dist/ anaconda_nightly_upload_token: ${{ secrets.ANACONDA_ORG_UPLOAD_TOKEN }} From 38df4a3028c3978d3a7f7521d8276c363ea78414 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 15 Oct 2024 17:46:55 +0200 Subject: [PATCH 22/25] MAINT: some cleanups for Python 3.13 support, no pre-releases needed anymore --- .github/workflows/wheel_tests_and_release.yml | 4 ++-- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index 8227a29b0..8674ea377 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -46,7 +46,7 @@ jobs: python-version: "3.10" - name: Install build deps; set CIBW environment variables - if: ${{ matrix.cibw_python }} == "cp313" || ${{ matrix.cibw_python }} == "cp313t" + if: ${{ matrix.cibw_python }} == "cp313t" run: | PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" CIBW_DEPS="pip install --upgrade pip build &&\ @@ -146,7 +146,7 @@ jobs: python-version: "3.12" - name: Install build deps; set CIBW environment variables - if: ${{ matrix.cibw_python }} == "cp313" || ${{ matrix.cibw_python }} == "cp313t" + if: ${{ matrix.cibw_python }} == "cp313t" run: | PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" CIBW_DEPS="pip install --upgrade pip build &&\ diff --git a/pyproject.toml b/pyproject.toml index 4326ffa9d..3c1a6ecb8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ requires = [ # redistributors can do this by installing the numpy version they like and # disabling build isolation. "numpy>=2.0.0; python_version<'3.13'", - "numpy>=2.1.0.rc1; python_version>='3.13'", + "numpy>=2.1.0; python_version>='3.13'", ] [project] From ffec299d17953da84f7f8f9ccc13d38b0dca4a5a Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 15 Oct 2024 17:49:35 +0200 Subject: [PATCH 23/25] CI: build free-threaded Windows wheels Note: we don't add scipy dependency on Windows, because it's not needed and there won't be win32 scipy wheels (and cp313t for amd64 is not yet available either). --- .github/workflows/wheel_tests_and_release.yml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index 8674ea377..776604cf6 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -190,7 +190,7 @@ jobs: matrix: os: [windows-latest] cibw_arch: ["AMD64", "x86"] - cibw_python: ["cp310", "cp311", "cp312", "cp313"] + cibw_python: ["cp310", "cp311", "cp312", "cp313", "cp313t"] steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: @@ -213,6 +213,19 @@ jobs: with: architecture: x64 + - name: Install build deps; set CIBW environment variables + if: ${{ matrix.cibw_python }} == "cp313t" + shell: bash -el {0} + run: | + PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" + CIBW_DEPS="pip install --upgrade pip build &&\ + pip install --pre -i $PYPI_URL cython numpy &&\ + pip install pytest meson-python ninja" + NO_BUILD_ISOLATION="pip; args: --no-build-isolation" + echo "CIBW_BEFORE_BUILD=$CIBW_DEPS" >> "$GITHUB_ENV" + echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" + echo "CIBW_BUILD_FRONTEND=$NO_BUILD_ISOLATION" >> "$GITHUB_ENV" + - name: Build Windows wheels for CPython uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 with: @@ -220,6 +233,7 @@ jobs: env: CIBW_BUILD: ${{ matrix.cibw_python }}-* CIBW_ARCHS_WINDOWS: ${{ matrix.cibw_arch }} + CIBW_FREE_THREADED_SUPPORT: True - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: From 93925d04462545a180530c3e6f51d2eac5419159 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 00:55:20 +0000 Subject: [PATCH 24/25] Bump the github-actions group with 3 updates Bumps the github-actions group with 3 updates: [pypa/cibuildwheel](/~https://github.com/pypa/cibuildwheel), [actions/upload-artifact](/~https://github.com/actions/upload-artifact) and [softprops/action-gh-release](/~https://github.com/softprops/action-gh-release). Updates `pypa/cibuildwheel` from 2.21.1 to 2.21.3 - [Release notes](/~https://github.com/pypa/cibuildwheel/releases) - [Changelog](/~https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](/~https://github.com/pypa/cibuildwheel/compare/d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23...7940a4c0e76eb2030e473a5f864f291f63ee879b) Updates `actions/upload-artifact` from 4.4.0 to 4.4.3 - [Release notes](/~https://github.com/actions/upload-artifact/releases) - [Commits](/~https://github.com/actions/upload-artifact/compare/50769540e7f4bd5e21e526ee35c689e35e0d6874...b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882) Updates `softprops/action-gh-release` from 2.0.8 to 2.0.9 - [Release notes](/~https://github.com/softprops/action-gh-release/releases) - [Changelog](/~https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](/~https://github.com/softprops/action-gh-release/compare/c062e08bd532815e2082a85e87e3ef29c3e6d191...e7a8f85e1c67a31e6ed99a94b41bd0b71bbee6b8) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: softprops/action-gh-release dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/emscripten.yml | 2 +- .github/workflows/wheel_tests_and_release.yml | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 242988201..d5cac985c 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v4 - name: Build and test PyWavelets - uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 + uses: pypa/cibuildwheel@7940a4c0e76eb2030e473a5f864f291f63ee879b # v2.21.3 env: CIBW_PLATFORM: pyodide CIBW_TEST_REQUIRES: pytest matplotlib diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index 776604cf6..2a07b2883 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -58,7 +58,7 @@ jobs: echo "CIBW_BUILD_FRONTEND=$NO_BUILD_ISOLATION" >> "$GITHUB_ENV" - name: Build the wheel - uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 + uses: pypa/cibuildwheel@7940a4c0e76eb2030e473a5f864f291f63ee879b # v2.21.3 with: output-dir: dist env: @@ -67,7 +67,7 @@ jobs: CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2 CIBW_FREE_THREADED_SUPPORT: True - - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -104,7 +104,7 @@ jobs: echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" - name: Build the wheel - uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 + uses: pypa/cibuildwheel@7940a4c0e76eb2030e473a5f864f291f63ee879b # v2.21.3 with: output-dir: dist env: @@ -112,7 +112,7 @@ jobs: CIBW_ARCHS_LINUX: ${{ matrix.cibw_arch }} CIBW_MANYLINUX_AARCH64_IMAGE: manylinux2014 CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_2 - - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: wheels_linux_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -159,7 +159,7 @@ jobs: - name: Build wheels for CPython (macOS) (x86_64) if: matrix.cibw_arch == 'x86_64' - uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 + uses: pypa/cibuildwheel@7940a4c0e76eb2030e473a5f864f291f63ee879b # v2.21.3 with: output-dir: dist env: @@ -168,7 +168,7 @@ jobs: - name: Build wheels for CPython (macOS) (arm64) if: matrix.cibw_arch == 'arm64' - uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 + uses: pypa/cibuildwheel@7940a4c0e76eb2030e473a5f864f291f63ee879b # v2.21.3 with: output-dir: dist env: @@ -176,7 +176,7 @@ jobs: CIBW_ARCHS_MACOS: ${{ matrix.cibw_arch }} CIBW_FREE_THREADED_SUPPORT: True - - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: wheels_macos_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -227,7 +227,7 @@ jobs: echo "CIBW_BUILD_FRONTEND=$NO_BUILD_ISOLATION" >> "$GITHUB_ENV" - name: Build Windows wheels for CPython - uses: pypa/cibuildwheel@d4a2945fcc8d13f20a1b99d461b8e844d5fc6e23 # v2.21.1 + uses: pypa/cibuildwheel@7940a4c0e76eb2030e473a5f864f291f63ee879b # v2.21.3 with: output-dir: dist env: @@ -235,7 +235,7 @@ jobs: CIBW_ARCHS_WINDOWS: ${{ matrix.cibw_arch }} CIBW_FREE_THREADED_SUPPORT: True - - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: wheels_windows_${{ matrix.cibw_arch }}_${{ matrix.cibw_python }} path: ./dist/*.whl @@ -290,7 +290,7 @@ jobs: TWINE_PASSWORD: ${{ secrets.TWINE_TOKEN }} - name: Github release - uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 + uses: softprops/action-gh-release@e7a8f85e1c67a31e6ed99a94b41bd0b71bbee6b8 # v2.0.9 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} From 551111675874cdb8fb13ab53bbe6c0c713e31931 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 1 Nov 2024 10:14:02 +0100 Subject: [PATCH 25/25] CI: fix Windows wheels, clean up cp313/cp313t build config --- .github/workflows/wheel_tests_and_release.yml | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/.github/workflows/wheel_tests_and_release.yml b/.github/workflows/wheel_tests_and_release.yml index 2a07b2883..95eb4ca68 100644 --- a/.github/workflows/wheel_tests_and_release.yml +++ b/.github/workflows/wheel_tests_and_release.yml @@ -49,9 +49,8 @@ jobs: if: ${{ matrix.cibw_python }} == "cp313t" run: | PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" - CIBW_DEPS="pip install --upgrade pip build &&\ - pip install --pre -i $PYPI_URL cython numpy scipy &&\ - pip install pytest meson-python ninja" + CIBW_DEPS="pip install --pre -i $PYPI_URL cython scipy &&\ + pip install numpy pytest meson-python ninja" NO_BUILD_ISOLATION="pip; args: --no-build-isolation" echo "CIBW_BEFORE_BUILD=$CIBW_DEPS" >> "$GITHUB_ENV" echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" @@ -95,14 +94,6 @@ jobs: with: platforms: arm64 - - name: Install test dep; set CIBW environment variables - # Can be removed once numpy 2.1.0 is released - if: ${{ matrix.cibw_python }} == "cp313" - run: | - PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" - CIBW_DEPS="pip install --pre -i $PYPI_URL numpy" - echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" - - name: Build the wheel uses: pypa/cibuildwheel@7940a4c0e76eb2030e473a5f864f291f63ee879b # v2.21.3 with: @@ -149,9 +140,8 @@ jobs: if: ${{ matrix.cibw_python }} == "cp313t" run: | PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" - CIBW_DEPS="pip install --upgrade pip build &&\ - pip install --pre -i $PYPI_URL cython numpy scipy &&\ - pip install pytest meson-python ninja" + CIBW_DEPS="pip install --pre -i $PYPI_URL cython scipy &&\ + pip install numpy pytest meson-python ninja" NO_BUILD_ISOLATION="pip; args: --no-build-isolation" echo "CIBW_BEFORE_BUILD=$CIBW_DEPS" >> "$GITHUB_ENV" echo "CIBW_BEFORE_TEST=$CIBW_DEPS" >> "$GITHUB_ENV" @@ -218,8 +208,7 @@ jobs: shell: bash -el {0} run: | PYPI_URL="https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" - CIBW_DEPS="pip install --upgrade pip build &&\ - pip install --pre -i $PYPI_URL cython numpy &&\ + CIBW_DEPS="pip install --pre -i $PYPI_URL cython numpy &&\ pip install pytest meson-python ninja" NO_BUILD_ISOLATION="pip; args: --no-build-isolation" echo "CIBW_BEFORE_BUILD=$CIBW_DEPS" >> "$GITHUB_ENV"