Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync README dependencies with pyproject.toml #12890

Merged
merged 11 commits into from
Oct 11, 2024
11 changes: 11 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ repos:
- id: toml-sort-fix
files: pyproject.toml

# dependencies
- repo: local
hooks:
- id: dependency-sync
name: Sync dependency list between pyproject.toml and README.rst
language: python
entry: ./tools/hooks/sync_dependencies.py
files: README\.rst$
additional_dependencies: ["mne"]


# The following are too slow to run on local commits, so let's only run on CIs:
#
# - repo: https://github.com/pre-commit/mirrors-mypy
Expand Down
39 changes: 6 additions & 33 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ only, use pip_ in a terminal:

$ pip install --upgrade mne

The current MNE-Python release requires Python 3.9 or higher. MNE-Python 0.17
was the last release to support Python 2.7.

For more complete instructions, including our standalone installers and more
advanced installation methods, please refer to the `installation guide`_.

Expand Down Expand Up @@ -73,42 +70,18 @@ Dependencies

The minimum required dependencies to run MNE-Python are:

.. ↓↓↓ BEGIN CORE DEPS LIST. DO NOT EDIT! HANDLED BY PRE-COMMIT HOOK ↓↓↓
- `Python <https://www.python.org>`__ ≥ 3.9
- `NumPy <https://numpy.org>`__ ≥ 1.24
- `SciPy <https://scipy.org>`__ ≥ 1.10
- `NumPy <https://numpy.org>`__ ≥ 1.23, < 3
drammock marked this conversation as resolved.
Show resolved Hide resolved
- `SciPy <https://scipy.org>`__ ≥ 1.9
- `Matplotlib <https://matplotlib.org>`__ ≥ 3.6
- `Pooch <https://www.fatiando.org/pooch/latest/>`__ ≥ 1.5
- `tqdm <https://tqdm.github.io>`__
- `Jinja2 <https://palletsprojects.com/p/jinja/>`__
- `decorator <https://github.com/micheles/decorator>`__
- `lazy_loader <https://pypi.org/project/lazy_loader/>`__

For full functionality, some functions require:

- `scikit-learn <https://scikit-learn.org/stable/>`__ ≥ 1.2
- `Joblib <https://joblib.readthedocs.io/en/latest/index.html>`__ ≥ 1.2 (for parallelization)
- `mne-qt-browser <https://github.com/mne-tools/mne-qt-browser>`__ ≥ 0.5 (for fast raw data visualization)
- `Qt <https://www.qt.io>`__ ≥ 5.15 via one of the following bindings (for fast raw data visualization and interactive 3D visualization):

- `PySide6 <https://doc.qt.io/qtforpython-6/>`__ ≥ 6.0
- `PyQt6 <https://www.riverbankcomputing.com/software/pyqt/>`__ ≥ 6.0
- `PyQt5 <https://www.riverbankcomputing.com/software/pyqt/>`__ ≥ 5.15

- `Numba <https://numba.pydata.org>`__ ≥ 0.56.4
- `NiBabel <https://nipy.org/nibabel/>`__ ≥ 3.2.1
- `OpenMEEG <https://openmeeg.github.io>`__ ≥ 2.5.6
- `pandas <https://pandas.pydata.org>`__ ≥ 1.5.2
- `Picard <https://pierreablin.github.io/picard/>`__ ≥ 0.3
- `CuPy <https://cupy.dev>`__ ≥ 9.0.0 (for NVIDIA CUDA acceleration)
- `DIPY <https://dipy.org>`__ ≥ 1.4.0
- `imageio <https://imageio.readthedocs.io/en/stable/>`__ ≥ 2.8.0
- `PyVista <https://pyvista.org>`__ ≥ 0.37 (for 3D visualization)
- `PyVistaQt <https://qtdocs.pyvista.org>`__ ≥ 0.9 (for 3D visualization)
- `mffpy <https://github.com/BEL-Public/mffpy>`__ ≥ 0.5.7
- `h5py <https://www.h5py.org>`__
- `h5io <https://github.com/h5io/h5io>`__
- `pymatreader <https://pymatreader.readthedocs.io/en/latest/>`__

- `lazy-loader <https://pypi.org/project/lazy_loader>`__ ≥ 0.3
- `packaging <https://packaging.pypa.io/en/stable/>`__
.. ↑↑↑ END CORE DEPS LIST. DO NOT EDIT! HANDLED BY PRE-COMMIT HOOK ↑↑↑

Contributing
^^^^^^^^^^^^
Expand Down
91 changes: 91 additions & 0 deletions tools/hooks/sync_dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env python

# Authors: The MNE-Python contributors.
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.

import re
from importlib.metadata import metadata
from pathlib import Path

from mne.utils import _pl, warn

README_PATH = Path(__file__).parents[2] / "README.rst"
BEGIN = ".. ↓↓↓ BEGIN CORE DEPS LIST. DO NOT EDIT! HANDLED BY PRE-COMMIT HOOK ↓↓↓"
END = ".. ↑↑↑ END CORE DEPS LIST. DO NOT EDIT! HANDLED BY PRE-COMMIT HOOK ↑↑↑"

CORE_DEPS_URLS = {
"Python": "https://www.python.org",
"NumPy": "https://numpy.org",
"SciPy": "https://scipy.org",
"Matplotlib": "https://matplotlib.org",
"Pooch": "https://www.fatiando.org/pooch/latest/",
"tqdm": "https://tqdm.github.io",
"Jinja2": "https://palletsprojects.com/p/jinja/",
"decorator": "https://github.com/micheles/decorator",
"lazy-loader": "https://pypi.org/project/lazy_loader",
"packaging": "https://packaging.pypa.io/en/stable/",
}


def _prettify_pin(pin):
if pin is None:
return ""
pins = pin.split(",")
replacements = {
"<=": " ≤ ",
">=": " ≥ ",
"<": " < ",
">": " > ",
}
for old, new in replacements.items():
pins = [p.replace(old, new) for p in pins]
pins = reversed(pins)
return ",".join(pins)


# get the dependency info
py_pin = metadata("mne").get("Requires-Python")
all_deps = metadata("mne").get_all("Requires-Dist")
core_deps = [f"python{py_pin}", *[dep for dep in all_deps if "extra ==" not in dep]]
pattern = re.compile(r"(?P<name>[A-Za-z_\-\d]+)(?P<pin>[<>=]+.*)?")
core_deps_pins = {
dep["name"]: _prettify_pin(dep["pin"]) for dep in map(pattern.match, core_deps)
}


# make sure our URLs dict is minimal and complete
missing_urls = set(core_deps_pins) - {dep.lower() for dep in CORE_DEPS_URLS}
extra_urls = {dep.lower() for dep in CORE_DEPS_URLS} - set(core_deps_pins)
update_msg = (
"please update `CORE_DEPS_URLS` mapping in `tools/hooks/sync_dependencies.py`."
)
if missing_urls:
_s = _pl(missing_urls)
raise RuntimeError(
f"Missing URL{_s} for package{_s} {', '.join(missing_urls)}; {update_msg}"
)
if extra_urls:
_s = _pl(extra_urls)
warn(f"Superfluous URL{_s} for package{_s} {', '.join(extra_urls)}; {update_msg}")
# construct the rST
core_deps_bullets = [
f"- `{key} <{url}>`__{core_deps_pins[key.lower()]}"
for key, url in CORE_DEPS_URLS.items()
]
core_deps_rst = "\n".join(core_deps_bullets) + "\n"
# rewrite the README file
skip = False
with open(README_PATH, "r+") as fid:
drammock marked this conversation as resolved.
Show resolved Hide resolved
lines = fid.readlines()
fid.seek(0)
for line in lines:
if line.strip() == BEGIN:
skip = True
fid.write(line)
fid.write(core_deps_rst)
if line.strip() == END:
skip = False
if not skip:
fid.write(line)
fid.truncate()
Loading