From 665f9a58c2c475bd3219f802376aa00cfd5a9df9 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Fri, 14 Nov 2025 10:57:44 -0600 Subject: [PATCH 1/8] placeholders --- .github/workflows/spec_zero.yml | 6 ++++++ .github/workflows/tests.yml | 3 +++ tools/github_actions_dependencies.sh | 2 ++ tools/github_actions_env_vars.sh | 2 ++ 4 files changed, 13 insertions(+) diff --git a/.github/workflows/spec_zero.yml b/.github/workflows/spec_zero.yml index 6a45f2876b6..73a1c6174f3 100644 --- a/.github/workflows/spec_zero.yml +++ b/.github/workflows/spec_zero.yml @@ -60,3 +60,9 @@ jobs: PR_NUM=$(gh pr create --base main --head spec_zero --title "MAINT: Update dependency specifiers" --body "Created by spec_zero [GitHub action](https://github.com/mne-tools/mne-python/actions/runs/${{ github.run_id }}).

*Adjustments may need to be made to shims in \`mne/fixes.py\` in this or another PR. \`git grep TODO VERSION\` is a good starting point for finding potential updates.*" --label "no-changelog-entry-needed") echo "Opened https://github.com/mne-tools/mne-python/pull/${PR_NUM}" >> $GITHUB_STEP_SUMMARY if: steps.status.outputs.dirty == 'true' + # TODO add one or more steps here to (re)create the lockfile based on the pins + # found in pyproject.toml. For now, any dependency that has a >= pin should + # become an == pin, and all other pins should be unchanged. Don't forget to + # pin Python version based on the `requires-python` field. Ideally, this step + # should only run if the pins in pyproject.toml have changed (e.g., see how + # we use "dirty" above to make the "Create PR" step conditional). diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 507bf4ebfb1..45b31234f68 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -152,7 +152,10 @@ jobs: python=${{ env.PYTHON_VERSION }} -v if: ${{ !startswith(matrix.kind, 'pip') }} + # TODO this ↑↑↑ will include matrix.kind == 'old' but we no longer want it to timeout-minutes: 20 + # TODO add a step here to install uv or pixi using their provided action + # it should only happen for matrix.kind == 'old' - run: bash ./tools/github_actions_dependencies.sh # Minimal commands on Linux (macOS stalls) - run: bash ./tools/get_minimal_commands.sh diff --git a/tools/github_actions_dependencies.sh b/tools/github_actions_dependencies.sh index f9a60080f4b..50dc24d5af9 100755 --- a/tools/github_actions_dependencies.sh +++ b/tools/github_actions_dependencies.sh @@ -27,6 +27,8 @@ if [ ! -z "$CONDA_ENV" ]; then GROUP="test_extra" EXTRAS="[hdf5]" fi +# TODO add a conditional branch here, that uses uv/pixi to recreate the "old" env +# from its lockfile, activate the env, and exit the bash script elif [[ "${MNE_CI_KIND}" == "pip" ]]; then GROUP="test_extra" EXTRAS="[full-pyside6]" diff --git a/tools/github_actions_env_vars.sh b/tools/github_actions_env_vars.sh index 9f424ae5f48..28326994b24 100755 --- a/tools/github_actions_env_vars.sh +++ b/tools/github_actions_env_vars.sh @@ -15,6 +15,8 @@ if [[ "$MNE_CI_KIND" == "pip"* ]]; then fi else # conda-like echo "Setting conda env vars for $MNE_CI_KIND" + # TODO pull this ↓↓↓ conditional branch out of its parent "else" clause, and + # adjust so it no longer sets a CONDA_ENV environment variable if [[ "$MNE_CI_KIND" == "old" ]]; then echo "CONDA_ENV=tools/environment_old.yml" | tee -a $GITHUB_ENV echo "MNE_IGNORE_WARNINGS_IN_TESTS=true" | tee -a $GITHUB_ENV From 5422e7a4b6984b18142a81f1e25666aa5c92cf69 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Fri, 19 Dec 2025 10:02:18 -0600 Subject: [PATCH 2/8] use resolution:lowest-direct; pin 2 unpinned deps to ensure resolution --- .github/workflows/spec_zero.yml | 11 +-- environment.yml | 4 +- pyproject.toml | 6 +- tools/pylock.ci-old.toml | 157 ++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 11 deletions(-) create mode 100644 tools/pylock.ci-old.toml diff --git a/.github/workflows/spec_zero.yml b/.github/workflows/spec_zero.yml index 73a1c6174f3..73e43fadc8a 100644 --- a/.github/workflows/spec_zero.yml +++ b/.github/workflows/spec_zero.yml @@ -43,7 +43,10 @@ jobs: python-version: '3.12' - run: pip install packaging requests tomlkit - run: python tools/dev/spec_zero_update_versions.py - - run: | + - name: Create lockfile for old CI + run: uv pip compile pyproject.toml --python-version 3.10 --resolution lowest-direct --output-file tools/pylock.ci-old.toml + - name: check if files changed + run: | git diff && git status --porcelain if [[ $(git status --porcelain) ]]; then echo "dirty=true" >> $GITHUB_OUTPUT @@ -60,9 +63,3 @@ jobs: PR_NUM=$(gh pr create --base main --head spec_zero --title "MAINT: Update dependency specifiers" --body "Created by spec_zero [GitHub action](https://github.com/mne-tools/mne-python/actions/runs/${{ github.run_id }}).

*Adjustments may need to be made to shims in \`mne/fixes.py\` in this or another PR. \`git grep TODO VERSION\` is a good starting point for finding potential updates.*" --label "no-changelog-entry-needed") echo "Opened https://github.com/mne-tools/mne-python/pull/${PR_NUM}" >> $GITHUB_STEP_SUMMARY if: steps.status.outputs.dirty == 'true' - # TODO add one or more steps here to (re)create the lockfile based on the pins - # found in pyproject.toml. For now, any dependency that has a >= pin should - # become an == pin, and all other pins should be unchanged. Don't forget to - # pin Python version based on the `requires-python` field. Ideally, this step - # should only run if the pins in pyproject.toml have changed (e.g., see how - # we use "dirty" above to make the "Create PR" step conditional). diff --git a/environment.yml b/environment.yml index b72d39925e4..a0b00f1bde2 100644 --- a/environment.yml +++ b/environment.yml @@ -7,7 +7,7 @@ dependencies: - antio >=0.5.0 - curryreader >=0.1.2 - darkdetect - - decorator + - decorator >=3.4 - defusedxml - dipy - edfio >=0.4.10 @@ -21,7 +21,7 @@ dependencies: - ipympl - ipython !=8.7.0 - ipywidgets - - jinja2 + - jinja2 >=2.1 - joblib - jupyter - lazy_loader >=0.3 diff --git a/pyproject.toml b/pyproject.toml index 4bcb69b0655..6d671b307de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,8 +90,8 @@ classifiers = [ "Topic :: Software Development", ] dependencies = [ - "decorator", - "jinja2", + "decorator >= 3.4", + "jinja2 >= 2.1", "lazy_loader >= 0.3", "matplotlib >= 3.8", # released 2023-09-15, will become 3.9 on 2026-05-15 "numpy >= 1.26, < 3", # released 2023-09-16, will become 2.0 on 2026-06-16 @@ -117,6 +117,8 @@ maintainers = [{email = "dan@mccloy.info", name = "Dan McCloy"}] name = "mne" readme = {content-type = "text/x-rst", file = "README.rst"} requires-python = ">= 3.10" +# ↑↑↑↑↑↑↑↑↑↑↑ when this changes, bump the `--python-version` in the `uv pip compile ...` +# ↑↑↑↑↑↑↑↑↑↑↑ command in `.github/workflows/spec_zero.yaml` (astral-sh/uv/#16333) scripts = {mne = "mne.commands.utils:main"} [project.optional-dependencies] diff --git a/tools/pylock.ci-old.toml b/tools/pylock.ci-old.toml new file mode 100644 index 00000000000..c97f6e07261 --- /dev/null +++ b/tools/pylock.ci-old.toml @@ -0,0 +1,157 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile pyproject.toml --python-version 3.10 --resolution lowest-direct --output-file tools/pylock.ci-old.toml +lock-version = "1.0" +created-by = "uv" +requires-python = ">=3.10" + +[[packages]] +name = "appdirs" +version = "1.4.4" +sdist = { url = "https://files.pythonhosted.org/packages/d7/d8/05696357e0311f5b5c316d7b95f46c669dd9c15aaeecbb48c7d0aeb88c40/appdirs-1.4.4.tar.gz", upload-time = 2020-05-11T07:59:51Z, size = 13470, hashes = { sha256 = "7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl", upload-time = 2020-05-11T07:59:49Z, size = 9566, hashes = { sha256 = "a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" } }] + +[[packages]] +name = "certifi" +version = "2025.11.12" +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", upload-time = 2025-11-12T02:54:51Z, size = 160538, hashes = { sha256 = "d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", upload-time = 2025-11-12T02:54:49Z, size = 159438, hashes = { sha256 = "97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b" } }] + +[[packages]] +name = "charset-normalizer" +version = "3.4.4" +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", upload-time = 2025-10-14T04:42:32Z, size = 129418, hashes = { sha256 = "94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a" } } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", upload-time = 2025-10-14T04:40:19Z, size = 153609, hashes = { sha256 = "9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313" } }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", upload-time = 2025-10-14T04:42:31Z, size = 53402, hashes = { sha256 = "7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f" } }, +] + +[[packages]] +name = "contourpy" +version = "1.3.2" +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", upload-time = 2025-04-15T17:47:53Z, size = 13466130, hashes = { sha256 = "b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2025-04-15T17:35:11Z, size = 325027, hashes = { sha256 = "ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631" } }] + +[[packages]] +name = "cycler" +version = "0.12.1" +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", upload-time = 2023-10-07T05:32:18Z, size = 7615, hashes = { sha256 = "88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", upload-time = 2023-10-07T05:32:16Z, size = 8321, hashes = { sha256 = "85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30" } }] + +[[packages]] +name = "decorator" +version = "5.1.0" +sdist = { url = "https://files.pythonhosted.org/packages/92/3c/34f8448b61809968052882b830f7d8d9a8e1c07048f70deb039ae599f73c/decorator-5.1.0.tar.gz", upload-time = 2021-09-11T05:30:17Z, size = 34900, hashes = { sha256 = "e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/3d/cc/d7b758e54779f7e465179427de7e78c601d3330d6c411ea7ba9ae2f38102/decorator-5.1.0-py3-none-any.whl", upload-time = 2021-09-11T05:30:14Z, size = 9061, hashes = { sha256 = "7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374" } }] + +[[packages]] +name = "fonttools" +version = "4.61.1" +sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", upload-time = 2025-12-12T17:31:24Z, size = 3565756, hashes = { sha256 = "6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69" } } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/69/4ca02ee367d2c98edcaeb83fc278d20972502ee071214ad9d8ca85e06080/fonttools-4.61.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", upload-time = 2025-12-12T17:29:34Z, size = 4859076, hashes = { sha256 = "a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6" } }, + { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", upload-time = 2025-12-12T17:31:21Z, size = 1148996, hashes = { sha256 = "17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371" } }, +] + +[[packages]] +name = "idna" +version = "3.11" +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", upload-time = 2025-10-12T14:55:20Z, size = 194582, hashes = { sha256 = "795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", upload-time = 2025-10-12T14:55:18Z, size = 71008, hashes = { sha256 = "771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea" } }] + +[[packages]] +name = "jinja2" +version = "2.10" +sdist = { url = "https://files.pythonhosted.org/packages/56/e6/332789f295cf22308386cf5bbd1f4e00ed11484299c5d7383378cf48ba47/Jinja2-2.10.tar.gz", upload-time = 2017-11-08T20:13:44Z, size = 261631, hashes = { sha256 = "f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl", upload-time = 2017-11-08T20:13:42Z, size = 126381, hashes = { sha256 = "74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd" } }] + +[[packages]] +name = "kiwisolver" +version = "1.4.9" +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", upload-time = 2025-08-10T21:27:49Z, size = 97564, hashes = { sha256 = "c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", upload-time = 2025-08-10T21:25:39Z, size = 1628458, hashes = { sha256 = "b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9" } }] + +[[packages]] +name = "lazy-loader" +version = "0.3" +sdist = { url = "https://files.pythonhosted.org/packages/0e/3a/1630a735bfdf9eb857a3b9a53317a1e1658ea97a1b4b39dcb0f71dae81f8/lazy_loader-0.3.tar.gz", upload-time = 2023-06-30T21:12:55Z, size = 12268, hashes = { sha256 = "3b68898e34f5b2a29daaaac172c6555512d0f32074f147e2254e4a6d9d838f37" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/a1/c3/65b3814e155836acacf720e5be3b5757130346670ac454fee29d3eda1381/lazy_loader-0.3-py3-none-any.whl", upload-time = 2023-06-30T21:12:51Z, size = 9087, hashes = { sha256 = "1e9e76ee8631e264c62ce10006718e80b2cfc74340d17d1031e0f84af7478554" } }] + +[[packages]] +name = "markupsafe" +version = "3.0.3" +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", upload-time = 2025-09-27T18:37:40Z, size = 80313, hashes = { sha256 = "722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", upload-time = 2025-09-27T18:36:08Z, size = 20681, hashes = { sha256 = "f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591" } }] + +[[packages]] +name = "matplotlib" +version = "3.8.0" +sdist = { url = "https://files.pythonhosted.org/packages/23/e1/77016194621fb1356aafeb2186f07b5dede62ea2043bf03f82325c4fccc5/matplotlib-3.8.0.tar.gz", upload-time = 2023-09-15T04:49:03Z, size = 35864435, hashes = { sha256 = "df8505e1c19d5c2c26aff3497a7cbd3ccfc2e97043d1e4db3e76afa399164b69" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/b5/24/aaccf324ce862bb82277e8814d2aebbb2a2c160d04e95aa2b8c9dc3137a9/matplotlib-3.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2023-09-15T04:50:03Z, size = 11610560, hashes = { sha256 = "d670b9348e712ec176de225d425f150dc8e37b13010d85233c539b547da0be39" } }] + +[[packages]] +name = "numpy" +version = "1.26.0" +sdist = { url = "https://files.pythonhosted.org/packages/55/b3/b13bce39ba82b7398c06d10446f5ffd5c07db39b09bd37370dc720c7951c/numpy-1.26.0.tar.gz", upload-time = 2023-09-16T20:12:58Z, size = 15633455, hashes = { sha256 = "f93fc78fe8bf15afe2b8d6b6499f1c73953169fad1e9a8dd086cdff3190e7fdf" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/9b/5a/f265a1ba3641d16b5480a217a6aed08cceef09cd173b568cd5351053472a/numpy-1.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2023-09-16T19:59:30Z, size = 18181958, hashes = { sha256 = "767254ad364991ccfc4d81b8152912e53e103ec192d1bb4ea6b1f5a7117040be" } }] + +[[packages]] +name = "packaging" +version = "20.0" +sdist = { url = "https://files.pythonhosted.org/packages/c7/cf/d84b72480a556d9bd4a191a91b0a8ea71cb48e6f6132f12d9d365c51bdb6/packaging-20.0.tar.gz", upload-time = 2020-01-06T06:25:08Z, size = 72663, hashes = { sha256 = "fe1d8331dfa7cc0a883b49d75fc76380b2ab2734b220fbb87d774e4fd4b851f8" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/d8/5b/3098db49a61ccc8583ffead6aedc226f08ff56dc03106b6ec54451e27a30/packaging-20.0-py2.py3-none-any.whl", upload-time = 2020-01-06T06:25:04Z, size = 36915, hashes = { sha256 = "aec3fdbb8bc9e4bb65f0634b9f551ced63983a529d6a8931817d52fdd0816ddb" } }] + +[[packages]] +name = "pillow" +version = "12.0.0" +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", upload-time = 2025-10-15T18:24:14Z, size = 47008828, hashes = { sha256 = "87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353" } } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/09/4de7cd03e33734ccd0c876f0251401f1314e819cbfd89a0fcb6e77927cc6/pillow-12.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", upload-time = 2025-10-15T18:21:33Z, size = 8024937, hashes = { sha256 = "c7b2a63fd6d5246349f3d3f37b14430d73ee7e8173154461785e43036ffa96ca" } }, + { url = "https://files.pythonhosted.org/packages/ed/1c/880921e98f525b9b44ce747ad1ea8f73fd7e992bafe3ca5e5644bf433dea/pillow-12.0.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", upload-time = 2025-10-15T18:21:37Z, size = 7026074, hashes = { sha256 = "d77153e14b709fd8b8af6f66a3afbb9ed6e9fc5ccf0b6b7e1ced7b036a228782" } }, +] + +[[packages]] +name = "pooch" +version = "1.5.0" +sdist = { url = "https://files.pythonhosted.org/packages/01/b8/aa2e51af6af8879fc9e61d75a31d16946c71b0abd07bde4ec2d99338fae5/pooch-1.5.0.tar.gz", upload-time = 2021-08-23T09:46:03Z, size = 60596, hashes = { sha256 = "9eaf36caccb78fbf1fd42acbeda9890b81de4d7e5823686ba49dc3010c21e1cf" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/1a/57/03a879380fe8b501e25617ea59a51a390ee9a5a09769945e8cb2c21ecaf1/pooch-1.5.0-py3-none-any.whl", upload-time = 2021-08-23T09:46:01Z, size = 56412, hashes = { sha256 = "54c9321a1cab8cd056ced497649eac69891066038319b31bebf13ec8ac79862b" } }] + +[[packages]] +name = "pyparsing" +version = "3.2.5" +sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", upload-time = 2025-09-21T04:11:06Z, size = 1099274, hashes = { sha256 = "2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", upload-time = 2025-09-21T04:11:04Z, size = 113890, hashes = { sha256 = "e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e" } }] + +[[packages]] +name = "python-dateutil" +version = "2.9.0.post0" +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", upload-time = 2024-03-01T18:36:20Z, size = 342432, hashes = { sha256 = "37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", upload-time = 2024-03-01T18:36:18Z, size = 229892, hashes = { sha256 = "a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" } }] + +[[packages]] +name = "requests" +version = "2.32.5" +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", upload-time = 2025-08-18T20:46:02Z, size = 134517, hashes = { sha256 = "dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", upload-time = 2025-08-18T20:46:00Z, size = 64738, hashes = { sha256 = "2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6" } }] + +[[packages]] +name = "scipy" +version = "1.11.1" +sdist = { url = "https://files.pythonhosted.org/packages/a6/98/fceb84466a74b8fe74ce2dcc3a0a89cb7b4a689d4775e0fb4c95f335ef6a/scipy-1.11.1.tar.gz", upload-time = 2023-06-28T22:30:20Z, size = 56031509, hashes = { sha256 = "fb5b492fa035334fd249f0973cc79ecad8b09c604b42a127a677b45a9a3d4289" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/14/f2/10fa23f0a6b9b2439c01579ae4a9b1849d4822e972515c8f92584bfda5e9/scipy-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2023-06-28T21:48:02Z, size = 36293635, hashes = { sha256 = "366a6a937110d80dca4f63b3f5b00cc89d36f678b2d124a01067b154e692bab1" } }] + +[[packages]] +name = "six" +version = "1.17.0" +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", upload-time = 2024-12-04T17:35:28Z, size = 34031, hashes = { sha256 = "ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", upload-time = 2024-12-04T17:35:26Z, size = 11050, hashes = { sha256 = "4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274" } }] + +[[packages]] +name = "tqdm" +version = "1.0" +sdist = { url = "https://files.pythonhosted.org/packages/ba/50/e6c90ecbc3a736ca8af22a52b3e665d32797b9f0cf6a79b7f4bd95dc2153/tqdm-1.0.tar.gz", upload-time = 2013-10-26T20:06:45Z, size = 1756, hashes = { sha256 = "d4972cfd62cf50bf88f20749b536258a3f48b31515dea3ad5edd5fe52e742c6c" } } + +[[packages]] +name = "urllib3" +version = "2.6.2" +sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", upload-time = 2025-12-11T15:56:40Z, size = 432930, hashes = { sha256 = "016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797" } } +wheels = [{ url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", upload-time = 2025-12-11T15:56:38Z, size = 131182, hashes = { sha256 = "ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd" } }] From ff35f5672297ce58d1c8a1a5c3eae638198c94f8 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Fri, 19 Dec 2025 13:18:19 -0600 Subject: [PATCH 3/8] install uv (and not micromamba) in old CI job Co-authored-by: Carina Forster --- .github/workflows/tests.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 45b31234f68..6e2da1ae4ff 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -151,11 +151,10 @@ jobs: create-args: >- python=${{ env.PYTHON_VERSION }} -v - if: ${{ !startswith(matrix.kind, 'pip') }} - # TODO this ↑↑↑ will include matrix.kind == 'old' but we no longer want it to + if: matrix.kind == 'conda' || matrix.kind == 'mamba' timeout-minutes: 20 - # TODO add a step here to install uv or pixi using their provided action - # it should only happen for matrix.kind == 'old' + - uses: astral-sh/setup-uv@v1 + if: matrix.kind == 'old' - run: bash ./tools/github_actions_dependencies.sh # Minimal commands on Linux (macOS stalls) - run: bash ./tools/get_minimal_commands.sh From 9fc848717e30dcf34ba51b412866de35b9530007 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Fri, 19 Dec 2025 13:45:04 -0600 Subject: [PATCH 4/8] don't set CONDA_ENV for old CI anymore --- tools/github_actions_env_vars.sh | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tools/github_actions_env_vars.sh b/tools/github_actions_env_vars.sh index 28326994b24..08a232ad6b3 100755 --- a/tools/github_actions_env_vars.sh +++ b/tools/github_actions_env_vars.sh @@ -13,15 +13,12 @@ if [[ "$MNE_CI_KIND" == "pip"* ]]; then else echo "MNE_QT_BACKEND=PySide6" | tee -a $GITHUB_ENV fi +elif [[ "$MNE_CI_KIND" == "old" ]]; then + echo "MNE_IGNORE_WARNINGS_IN_TESTS=true" | tee -a $GITHUB_ENV + echo "MNE_SKIP_NETWORK_TESTS=1" | tee -a $GITHUB_ENV + echo "MNE_QT_BACKEND=PyQt5" | tee -a $GITHUB_ENV else # conda-like echo "Setting conda env vars for $MNE_CI_KIND" - # TODO pull this ↓↓↓ conditional branch out of its parent "else" clause, and - # adjust so it no longer sets a CONDA_ENV environment variable - if [[ "$MNE_CI_KIND" == "old" ]]; then - echo "CONDA_ENV=tools/environment_old.yml" | tee -a $GITHUB_ENV - echo "MNE_IGNORE_WARNINGS_IN_TESTS=true" | tee -a $GITHUB_ENV - echo "MNE_SKIP_NETWORK_TESTS=1" | tee -a $GITHUB_ENV - echo "MNE_QT_BACKEND=PyQt5" | tee -a $GITHUB_ENV elif [[ "$MNE_CI_KIND" == "minimal" ]]; then echo "CONDA_ENV=tools/environment_minimal.yml" | tee -a $GITHUB_ENV echo "MNE_QT_BACKEND=PySide6" | tee -a $GITHUB_ENV From 7e0af0cca0da2aeeb1304bb6970c6c0197148127 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Fri, 19 Dec 2025 13:57:04 -0600 Subject: [PATCH 5/8] restore from lockfile when setting up old CI --- pyproject.toml | 3 ++- tools/github_actions_dependencies.sh | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6d671b307de..b4ab26cf5f9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -118,7 +118,8 @@ name = "mne" readme = {content-type = "text/x-rst", file = "README.rst"} requires-python = ">= 3.10" # ↑↑↑↑↑↑↑↑↑↑↑ when this changes, bump the `--python-version` in the `uv pip compile ...` -# ↑↑↑↑↑↑↑↑↑↑↑ command in `.github/workflows/spec_zero.yaml` (astral-sh/uv/#16333) +# command in `.github/workflows/spec_zero.yaml` (astral-sh/uv/#16333), and also the +# `--python` version in the `uv venv` command in `tools/github_actions_dependencies.sh` scripts = {mne = "mne.commands.utils:main"} [project.optional-dependencies] diff --git a/tools/github_actions_dependencies.sh b/tools/github_actions_dependencies.sh index 50dc24d5af9..5741635787d 100755 --- a/tools/github_actions_dependencies.sh +++ b/tools/github_actions_dependencies.sh @@ -27,8 +27,13 @@ if [ ! -z "$CONDA_ENV" ]; then GROUP="test_extra" EXTRAS="[hdf5]" fi -# TODO add a conditional branch here, that uses uv/pixi to recreate the "old" env -# from its lockfile, activate the env, and exit the bash script +elif [[ ${MNE_CI_KIND} == "old" ]]; then + GROUP="test" + EXTRAS="" + STD_ARGS="--progress-bar off" + uv venv --python 3.10 + uv pip sync ${SCRIPT_DIR}/pylock.ci-old.toml + source .venv/bin/activate elif [[ "${MNE_CI_KIND}" == "pip" ]]; then GROUP="test_extra" EXTRAS="[full-pyside6]" From c5fb37cd7b8aaf7750a89ddac82baacabb107fd2 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Fri, 19 Dec 2025 15:19:10 -0600 Subject: [PATCH 6/8] elif --- tools/github_actions_env_vars.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/github_actions_env_vars.sh b/tools/github_actions_env_vars.sh index 08a232ad6b3..ca95fca4d2c 100755 --- a/tools/github_actions_env_vars.sh +++ b/tools/github_actions_env_vars.sh @@ -19,7 +19,7 @@ elif [[ "$MNE_CI_KIND" == "old" ]]; then echo "MNE_QT_BACKEND=PyQt5" | tee -a $GITHUB_ENV else # conda-like echo "Setting conda env vars for $MNE_CI_KIND" - elif [[ "$MNE_CI_KIND" == "minimal" ]]; then + if [[ "$MNE_CI_KIND" == "minimal" ]]; then echo "CONDA_ENV=tools/environment_minimal.yml" | tee -a $GITHUB_ENV echo "MNE_QT_BACKEND=PySide6" | tee -a $GITHUB_ENV else # conda, mamba (use warning level for completeness) From 7a342c63d0564c0998a4d8d79a39c66ecc308f3f Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Fri, 26 Dec 2025 17:33:52 -0600 Subject: [PATCH 7/8] update actions --- .github/workflows/spec_zero.yml | 4 +++- tools/github_actions_dependencies.sh | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spec_zero.yml b/.github/workflows/spec_zero.yml index 79a4013f2ed..fac86fd4769 100644 --- a/.github/workflows/spec_zero.yml +++ b/.github/workflows/spec_zero.yml @@ -47,7 +47,9 @@ jobs: - run: pip install packaging requests tomlkit - run: python tools/dev/spec_zero_update_versions.py - name: Create lockfile for old CI - run: uv pip compile pyproject.toml --python-version 3.10 --resolution lowest-direct --output-file tools/pylock.ci-old.toml + # uv pip compile requires setting the python version explicitly in the command :( + # run: uv pip compile --python "3.10" --python-platform "x86_64-unknown-linux-gnu" --group test --resolution lowest-direct --format pylock.toml --output-file tools/pylock.old-ci.toml + run: uv export --format pylock.toml --group test --resolution lowest-direct --output-file tools/pylock.old-ci.toml - name: check if files changed run: | git diff && git status --porcelain diff --git a/tools/github_actions_dependencies.sh b/tools/github_actions_dependencies.sh index 5741635787d..636cadd04e1 100755 --- a/tools/github_actions_dependencies.sh +++ b/tools/github_actions_dependencies.sh @@ -28,7 +28,7 @@ if [ ! -z "$CONDA_ENV" ]; then EXTRAS="[hdf5]" fi elif [[ ${MNE_CI_KIND} == "old" ]]; then - GROUP="test" + GROUP="" # group "test" already included when pylock file generated EXTRAS="" STD_ARGS="--progress-bar off" uv venv --python 3.10 From 21eae2ac4e2b0711baa7ef6087c0df9dd53f7462 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Fri, 26 Dec 2025 17:34:29 -0600 Subject: [PATCH 8/8] update dep pins to get uv export to actually work --- environment.yml | 20 ++++++++++---------- pyproject.toml | 40 ++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/environment.yml b/environment.yml index 7dd63efa1a8..7ccf9b81ca3 100644 --- a/environment.yml +++ b/environment.yml @@ -7,32 +7,32 @@ dependencies: - antio >=0.5.0 - curryreader >=0.1.2 - darkdetect - - decorator >=3.4 + - decorator >=3.5 - defusedxml - - dipy + - dipy >=0.8 - edfio >=0.4.10 - eeglabio - filelock >=3.18.0 - h5io >=0.2.4 - - h5py + - h5py >=2.4 - imageio >=2.6.1 - imageio-ffmpeg >=0.4.1 - ipyevents - ipympl - - ipython !=8.7.0 + - ipython >=2.0,!=8.7.0 - ipywidgets - - jinja2 >=2.1 - - joblib + - jinja2 >=2.7 + - joblib >=0.8 - jupyter - lazy_loader >=0.3 - mamba - matplotlib >=3.8 - mffpy >=0.5.7 - mne-qt-browser - - nibabel + - nibabel >=2.0 - nilearn - nomkl - - numba + - numba >=0.35 - numpy >=1.26,<3 - openmeeg >=2.5.7 - packaging @@ -45,7 +45,7 @@ dependencies: - pymatreader - PySide6 !=6.9.1 - python-neo - - python-picard + - python-picard >=0.4 - pyvista >=0.43 - pyvistaqt >=0.11 - qdarkstyle !=3.2.2 @@ -54,7 +54,7 @@ dependencies: - scipy >=1.11 - sip - snirf - - statsmodels + - statsmodels >=0.6 - threadpoolctl - tqdm - traitlets diff --git a/pyproject.toml b/pyproject.toml index 4fabdcf0127..1d29dff8ae8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,21 +1,21 @@ [build-system] build-backend = "hatchling.build" -requires = ["hatch-vcs", "hatchling"] +requires = ["hatch-vcs", "hatchling >= 1.27"] [dependency-groups] -dev = ["pip >= 25.1", "rcssmin", {include-group = "doc"}, {include-group = "test_extra"}] +dev = ["pip >= 25.1", "rcssmin >= 1.1", {include-group = "doc"}, {include-group = "test_extra"}] # Dependencies for building the documentation doc = [ "graphviz", "intersphinx_registry >= 0.2405.27", "ipython != 8.7.0", # also in "full-no-qt" and "test" - "memory_profiler", + "memory_profiler >= 0.16", "mne-bids", "mne-connectivity", "mne-gui-addons", "neo", - "numpydoc", - "openneuro-py", + "numpydoc >= 0.5", + "openneuro-py >= 2020.1", "psutil", "pydata_sphinx_theme >= 0.15.2", "pygments >= 2.13", @@ -24,7 +24,7 @@ doc = [ "pyxdf", "pyzmq != 24.0.0", "scikit-learn", - "seaborn != 0.11.2", + "seaborn >= 0.5, != 0.11.2", "selenium >= 4.27.1", "sphinx >= 6", "sphinx-design", @@ -37,12 +37,12 @@ doc = [ test = [ "codespell", "ipython != 8.7.0", # for testing notebook backend; also in "full-no-qt" and "doc" - "mypy", + "mypy >= 0.14", "numpydoc", "pre-commit", "pytest >= 8.0", "pytest-cov", - "pytest-qt", + "pytest-qt >= 1.1", "pytest-rerunfailures", "pytest-timeout", "ruff", @@ -50,7 +50,7 @@ test = [ "tomli; python_version<'3.11'", "twine", "vulture", - "wheel", + "wheel >= 0.21", ] # Dependencies for being able to run additional tests (rare/CIs/advanced devs) # Changes here should be reflected in the mne/utils/config.py dev dependencies section @@ -64,7 +64,7 @@ test_extra = [ "nbclient", "nbformat", "neo", - "nitime", + "nitime >= 0.7", "pybv", "snirf", "sphinx-gallery", @@ -90,8 +90,8 @@ classifiers = [ "Topic :: Software Development", ] dependencies = [ - "decorator >= 3.4", - "jinja2 >= 2.1", + "decorator >= 3.5", + "jinja2 >= 2.7", "lazy_loader >= 0.3", "matplotlib >= 3.8", # released 2023-09-15, will become 3.9 on 2026-05-15 "numpy >= 1.26, < 3", # released 2023-09-16, will become 2.0 on 2026-06-16 @@ -136,34 +136,34 @@ full-no-qt = [ "curryreader >= 0.1.2", "darkdetect", "defusedxml", - "dipy", + "dipy >= 0.8", "edfio >= 0.4.10", "eeglabio", "filelock >= 3.18.0", - "h5py", + "h5py >= 2.4", "imageio >= 2.6.1", "imageio-ffmpeg >= 0.4.1", "ipyevents", "ipympl", - "ipython != 8.7.0", # for notebook backend; also in "doc" and "test" + "ipython >= 2.0, != 8.7.0", # for notebook backend; also in "doc" and "test" "ipywidgets", - "joblib", + "joblib >= 0.8", "jupyter", "mffpy >= 0.5.7", "mne-qt-browser", "mne[hdf5]", "neo", "nest-asyncio2", - "nibabel", + "nibabel >= 2.0", "nilearn", - "numba", + "numba >= 0.35", "openmeeg >= 2.5.7", "pandas >= 2.1", # released 2023-08-30, will become 2.2 on 2026-01-19 "pillow", # for `Brain.save_image` and `mne.Report` "pyarrow", # only needed to avoid a deprecation warning in pandas "pybv", "pyobjc-framework-Cocoa >= 5.2.0; platform_system == 'Darwin'", - "python-picard", + "python-picard >= 0.4", "pyvista >= 0.43", # released 2023-12-07, will become 0.44 on 2026-07-07 "pyvistaqt >= 0.11", # released 2023-06-30, no newer version available "qdarkstyle != 3.2.2", @@ -171,7 +171,7 @@ full-no-qt = [ "scikit-learn >= 1.3", # released 2023-06-30, will become 1.4 on 2026-01-17 "sip", "snirf", - "statsmodels", + "statsmodels >= 0.6", "threadpoolctl", "traitlets", "trame",