Skip to content

Commit 922a780

Browse files
Sync README dependencies with pyproject.toml (#12890)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 72faa3c commit 922a780

File tree

4 files changed

+118
-33
lines changed

4 files changed

+118
-33
lines changed

.pre-commit-config.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,21 @@ repos:
6363
- id: toml-sort-fix
6464
files: pyproject.toml
6565

66+
# dependencies
67+
- repo: local
68+
hooks:
69+
- id: dependency-sync
70+
name: Sync dependency list between pyproject.toml and README.rst
71+
language: python
72+
entry: ./tools/hooks/sync_dependencies.py
73+
files: pyproject.toml
74+
additional_dependencies: ["mne"]
75+
76+
77+
# these should *not* be run on CIs:
78+
ci:
79+
skip: [dependency-sync] # needs MNE to work, which exceeds the free tier space alloc.
80+
6681
# The following are too slow to run on local commits, so let's only run on CIs:
6782
#
6883
# - repo: https://github.com/pre-commit/mirrors-mypy

README.rst

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,6 @@ only, use pip_ in a terminal:
4343
4444
$ pip install --upgrade mne
4545
46-
The current MNE-Python release requires Python 3.9 or higher. MNE-Python 0.17
47-
was the last release to support Python 2.7.
48-
4946
For more complete instructions, including our standalone installers and more
5047
advanced installation methods, please refer to the `installation guide`_.
5148

@@ -73,42 +70,20 @@ Dependencies
7370

7471
The minimum required dependencies to run MNE-Python are:
7572

73+
.. ↓↓↓ BEGIN CORE DEPS LIST. DO NOT EDIT! HANDLED BY PRE-COMMIT HOOK ↓↓↓
74+
7675
- `Python <https://www.python.org>`__ ≥ 3.9
77-
- `NumPy <https://numpy.org>`__ ≥ 1.24
78-
- `SciPy <https://scipy.org>`__ ≥ 1.10
76+
- `NumPy <https://numpy.org>`__ ≥ 1.23
77+
- `SciPy <https://scipy.org>`__ ≥ 1.9
7978
- `Matplotlib <https://matplotlib.org>`__ ≥ 3.6
8079
- `Pooch <https://www.fatiando.org/pooch/latest/>`__ ≥ 1.5
8180
- `tqdm <https://tqdm.github.io>`__
8281
- `Jinja2 <https://palletsprojects.com/p/jinja/>`__
8382
- `decorator <https://github.com/micheles/decorator>`__
84-
- `lazy_loader <https://pypi.org/project/lazy_loader/>`__
85-
86-
For full functionality, some functions require:
87-
88-
- `scikit-learn <https://scikit-learn.org/stable/>`__ ≥ 1.2
89-
- `Joblib <https://joblib.readthedocs.io/en/latest/index.html>`__ ≥ 1.2 (for parallelization)
90-
- `mne-qt-browser <https://github.com/mne-tools/mne-qt-browser>`__ ≥ 0.5 (for fast raw data visualization)
91-
- `Qt <https://www.qt.io>`__ ≥ 5.15 via one of the following bindings (for fast raw data visualization and interactive 3D visualization):
92-
93-
- `PySide6 <https://doc.qt.io/qtforpython-6/>`__ ≥ 6.0
94-
- `PyQt6 <https://www.riverbankcomputing.com/software/pyqt/>`__ ≥ 6.0
95-
- `PyQt5 <https://www.riverbankcomputing.com/software/pyqt/>`__ ≥ 5.15
96-
97-
- `Numba <https://numba.pydata.org>`__ ≥ 0.56.4
98-
- `NiBabel <https://nipy.org/nibabel/>`__ ≥ 3.2.1
99-
- `OpenMEEG <https://openmeeg.github.io>`__ ≥ 2.5.6
100-
- `pandas <https://pandas.pydata.org>`__ ≥ 1.5.2
101-
- `Picard <https://pierreablin.github.io/picard/>`__ ≥ 0.3
102-
- `CuPy <https://cupy.dev>`__ ≥ 9.0.0 (for NVIDIA CUDA acceleration)
103-
- `DIPY <https://dipy.org>`__ ≥ 1.4.0
104-
- `imageio <https://imageio.readthedocs.io/en/stable/>`__ ≥ 2.8.0
105-
- `PyVista <https://pyvista.org>`__ ≥ 0.37 (for 3D visualization)
106-
- `PyVistaQt <https://qtdocs.pyvista.org>`__ ≥ 0.9 (for 3D visualization)
107-
- `mffpy <https://github.com/BEL-Public/mffpy>`__ ≥ 0.5.7
108-
- `h5py <https://www.h5py.org>`__
109-
- `h5io <https://github.com/h5io/h5io>`__
110-
- `pymatreader <https://pymatreader.readthedocs.io/en/latest/>`__
83+
- `lazy-loader <https://pypi.org/project/lazy_loader>`__ ≥ 0.3
84+
- `packaging <https://packaging.pypa.io/en/stable/>`__
11185

86+
.. ↑↑↑ END CORE DEPS LIST. DO NOT EDIT! HANDLED BY PRE-COMMIT HOOK ↑↑↑
11287
11388
Contributing
11489
^^^^^^^^^^^^

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ scripts = {mne = "mne.commands.utils:main"}
5151
[project.optional-dependencies]
5252
# Leave this one here for backward-compat
5353
data = []
54-
dev = ["mne[test,doc]", "rcssmin"]
54+
dev = ["mne[doc,test]", "rcssmin"]
5555
# Dependencies for building the documentation
5656
doc = [
5757
"graphviz",

tools/hooks/sync_dependencies.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#!/usr/bin/env python
2+
3+
# Authors: The MNE-Python contributors.
4+
# License: BSD-3-Clause
5+
# Copyright the MNE-Python contributors.
6+
7+
import re
8+
from importlib.metadata import metadata
9+
from pathlib import Path
10+
11+
from mne.utils import _pl, warn
12+
13+
README_PATH = Path(__file__).parents[2] / "README.rst"
14+
BEGIN = ".. ↓↓↓ BEGIN CORE DEPS LIST. DO NOT EDIT! HANDLED BY PRE-COMMIT HOOK ↓↓↓"
15+
END = ".. ↑↑↑ END CORE DEPS LIST. DO NOT EDIT! HANDLED BY PRE-COMMIT HOOK ↑↑↑"
16+
17+
CORE_DEPS_URLS = {
18+
"Python": "https://www.python.org",
19+
"NumPy": "https://numpy.org",
20+
"SciPy": "https://scipy.org",
21+
"Matplotlib": "https://matplotlib.org",
22+
"Pooch": "https://www.fatiando.org/pooch/latest/",
23+
"tqdm": "https://tqdm.github.io",
24+
"Jinja2": "https://palletsprojects.com/p/jinja/",
25+
"decorator": "https://github.com/micheles/decorator",
26+
"lazy-loader": "https://pypi.org/project/lazy_loader",
27+
"packaging": "https://packaging.pypa.io/en/stable/",
28+
}
29+
30+
31+
def _prettify_pin(pin):
32+
if pin is None:
33+
return ""
34+
pins = pin.split(",")
35+
replacements = {
36+
"<=": " ≤ ",
37+
">=": " ≥ ",
38+
"<": " < ",
39+
">": " > ",
40+
}
41+
for old, new in replacements.items():
42+
pins = [p.replace(old, new) for p in pins]
43+
pins = reversed(pins)
44+
return ",".join(pins)
45+
46+
47+
# get the dependency info
48+
py_pin = metadata("mne").get("Requires-Python")
49+
all_deps = metadata("mne").get_all("Requires-Dist")
50+
core_deps = [f"python{py_pin}", *[dep for dep in all_deps if "extra ==" not in dep]]
51+
pattern = re.compile(r"(?P<name>[A-Za-z_\-\d]+)(?P<pin>[<>=]+.*)?")
52+
core_deps_pins = {
53+
dep["name"]: _prettify_pin(dep["pin"]) for dep in map(pattern.match, core_deps)
54+
}
55+
# don't show upper pin on NumPy (not important for users, just devs)
56+
new_pin = core_deps_pins["numpy"].split(",")
57+
new_pin.remove(" < 3")
58+
core_deps_pins["numpy"] = new_pin[0]
59+
60+
# make sure our URLs dict is minimal and complete
61+
missing_urls = set(core_deps_pins) - {dep.lower() for dep in CORE_DEPS_URLS}
62+
extra_urls = {dep.lower() for dep in CORE_DEPS_URLS} - set(core_deps_pins)
63+
update_msg = (
64+
"please update `CORE_DEPS_URLS` mapping in `tools/hooks/sync_dependencies.py`."
65+
)
66+
if missing_urls:
67+
_s = _pl(missing_urls)
68+
raise RuntimeError(
69+
f"Missing URL{_s} for package{_s} {', '.join(missing_urls)}; {update_msg}"
70+
)
71+
if extra_urls:
72+
_s = _pl(extra_urls)
73+
warn(f"Superfluous URL{_s} for package{_s} {', '.join(extra_urls)}; {update_msg}")
74+
75+
# construct the rST
76+
core_deps_bullets = [
77+
f"- `{key} <{url}>`__{core_deps_pins[key.lower()]}"
78+
for key, url in CORE_DEPS_URLS.items()
79+
]
80+
core_deps_rst = "\n" + "\n".join(core_deps_bullets) + "\n"
81+
82+
# rewrite the README file
83+
lines = README_PATH.read_text("utf-8").splitlines()
84+
out_lines = list()
85+
skip = False
86+
for line in lines:
87+
if line.strip() == BEGIN:
88+
skip = True
89+
out_lines.append(line)
90+
out_lines.append(core_deps_rst)
91+
if line.strip() == END:
92+
skip = False
93+
if not skip:
94+
out_lines.append(line)
95+
README_PATH.write_text("\n".join(out_lines) + "\n", encoding="utf-8")

0 commit comments

Comments
 (0)