Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
- Add dialog for automatic epoch artifact detection with configurable methods ([#558](https://github.com/cbrnr/mnelab/pull/558) by [Fabian Schellander](https://github.com/SchellanderF))
- Add MNE log messages viewer to history dialog ([#561](https://github.com/cbrnr/mnelab/pull/561) by [Clemens Brunner](https://github.com/cbrnr))

### 🔧 Fixed
- Fix dependency detection in standalone versions that could have caused some features to not work ([#562](https://github.com/cbrnr/mnelab/pull/562)) by [Clemens Brunner](https://github.com/cbrnr))

## [1.2.0] · 2026-02-17
### ✨ Added
- Add support for BVRF import via PyBVRF ([#560](https://github.com/cbrnr/mnelab/pull/560) by [Clemens Brunner](https://github.com/cbrnr))
Expand Down
20 changes: 15 additions & 5 deletions src/mnelab/utils/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# License: BSD (3-clause)

from importlib import metadata
from importlib import import_module, metadata

required = [
"mne",
Expand All @@ -21,14 +21,24 @@
optional = ["autoreject", "mne-qt-browser", "picard", "sklearn"]

_distribution_names = {
"python-picard": "picard",
"scikit-learn": "sklearn",
"picard": "python-picard",
"sklearn": "scikit-learn",
}
_import_names = {
"pyside6": "PySide6",
}

have = {}
for dep in required + optional:
distribution_name = {v: k for k, v in _distribution_names.items()}.get(dep, dep)
distribution_name = _distribution_names.get(dep, dep)
import_name = _import_names.get(dep, dep).replace("-", "_")
try:
version = metadata.version(distribution_name)
except metadata.PackageNotFoundError:
version = False
try:
mod = import_module(import_name)
except ImportError:
version = False
else:
version = getattr(mod, "__version__", None) or "unknown"
have[distribution_name] = version
71 changes: 71 additions & 0 deletions tests/test_dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# © MNELAB developers
#
# License: BSD (3-clause)

import importlib
import sys
from importlib import metadata as importlib_metadata
from importlib import util as importlib_util
from pathlib import Path
from types import SimpleNamespace


def _load_dependencies_module(monkeypatch, modules):
module_path = (
Path(__file__).resolve().parents[1]
/ "src"
/ "mnelab"
/ "utils"
/ "dependencies.py"
)

def fake_metadata_version(_name):
raise importlib_metadata.PackageNotFoundError

def fake_import_module(name):
if name in modules:
return modules[name]
raise ImportError(name)

monkeypatch.setattr(importlib_metadata, "version", fake_metadata_version)
monkeypatch.setattr(importlib, "import_module", fake_import_module)

module_name = "mnelab_test_dependencies"
sys.modules.pop(module_name, None)
spec = importlib_util.spec_from_file_location(module_name, module_path)
if spec is None or spec.loader is None:
raise RuntimeError("Could not create module spec for dependencies.py")
module = importlib_util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
return module


def test_standalone_fallback_detects_importable_dependencies(monkeypatch):
modules = {
"PySide6": SimpleNamespace(__version__="6.9.4"),
"matplotlib": SimpleNamespace(__version__="3.10.0"),
"scipy": SimpleNamespace(__version__="1.14.1"),
"pyxdf": SimpleNamespace(__version__="1.16.0"),
"pybvrf": SimpleNamespace(__version__="0.1.1"),
"black": SimpleNamespace(__version__="25.0.0"),
"onnx": SimpleNamespace(__version__="1.20.0"),
"picard": SimpleNamespace(__version__="0.8.0"),
}

dependencies = _load_dependencies_module(monkeypatch, modules)

assert dependencies.have["pyside6"] == "6.9.4"
assert dependencies.have["matplotlib"] == "3.10.0"
assert dependencies.have["scipy"] == "1.14.1"
assert dependencies.have["pyxdf"] == "1.16.0"
assert dependencies.have["pybvrf"] == "0.1.1"
assert dependencies.have["black"] == "25.0.0"
assert dependencies.have["onnx"] == "1.20.0"
assert dependencies.have["python-picard"] == "0.8.0"


def test_standalone_fallback_keeps_false_for_missing_import(monkeypatch):
dependencies = _load_dependencies_module(monkeypatch, modules={})

assert dependencies.have["pyside6"] is False