Skip to content

Commit

Permalink
MAINT: Compat with MNE 1.8 birthday date (#1278)
Browse files Browse the repository at this point in the history
* MAINT: Compat with MNE 1.8 birthday date

* FIX: Write, too

* Update whats_new.rst

---------

Co-authored-by: Stefan Appelhoff <[email protected]>
  • Loading branch information
larsoner and sappelhoff authored Jul 19, 2024
1 parent 3c020d9 commit af12bc4
Show file tree
Hide file tree
Showing 14 changed files with 57 additions and 29 deletions.
8 changes: 7 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,13 @@ jobs:
name: Build the documentation
no_output_timeout: 30m
command: |
make build-doc
make build-doc 2>&1 | tee sphinx_log.txt
- run:
name: Check sphinx log for warnings (which are treated as errors)
when: always
command: |
! grep "^.*WARNING: .*$" sphinx_log.txt
- persist_to_workspace:
root: doc/_build
Expand Down
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ repos:
- id: ruff
name: ruff mne_bids/
files: ^mne_bids/
args: ["--fix"]
- id: ruff
name: ruff examples/
# D103: missing docstring in public function
Expand Down
5 changes: 3 additions & 2 deletions doc/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The following authors contributed for the first time. Thank you so much! 🤩
The following authors had contributed before. Thank you for sticking around! 🤘

* `Daniel McCloy`_
* `Eric Larson`_
* `Stefan Appelhoff`_

Detailed list of changes
Expand All @@ -45,12 +46,12 @@ Detailed list of changes
🪲 Bug fixes
^^^^^^^^^^^^

- When anonymizing the date of a recording, MNE-BIDS will no longer error during `~mne_bids.write_raw_bids` if passing a `~mne.io.Raw` instance to ``empty_room``. By `Daniel McCloy`_ (:gh:`1270`)
- When anonymizing the date of a recording, MNE-BIDS will no longer error during `~mne_bids.write_raw_bids` if passing a `~mne.io.Raw` instance to ``empty_room``, by `Daniel McCloy`_ (:gh:`1270`)

⚕️ Code health
^^^^^^^^^^^^^^

- nothing yet
- Keep MNE-BIDS up to date with recent changes on participant birthday date handling in MNE-Python, by `Eric Larson`_ (gh:1278:)

:doc:`Find out what was new in previous releases <whats_new_previous_releases>`

Expand Down
12 changes: 6 additions & 6 deletions doc/whats_new_previous_releases.rst
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ API and behavior changes

- Reading BIDS data with ``"HeadCoilFrequency"`` and ``"PowerLineFrequency"`` data specified in JSON sidecars will only "warn" in case of mismatches between Raw and JSON data, by `Franziska von Albedyll`_ (:gh:`855`)

- Accessing :attr:`mne_bids.BIDSPath.fpath` emit a warning anymore if the path does not exist. This behavior was unreliable and yielded confusing error messages in certain use cases. Use `mne_bids.BIDSPath.fpath.exists()` to check whether the path exists in the file system, by `Richard Höchenberger`_ (:gh:`904`)
- Accessing :attr:`mne_bids.BIDSPath.fpath` emit a warning anymore if the path does not exist. This behavior was unreliable and yielded confusing error messages in certain use cases. Use ``mne_bids.BIDSPath.fpath.exists()`` to check whether the path exists in the file system, by `Richard Höchenberger`_ (:gh:`904`)

- :func:`mne_bids.get_entity_vals` gained a new parameter, ``ignore_dirs``, to exclude directories from the search, by `Adam Li`_ and `Richard Höchenberger`_ (:gh:`899`, :gh:`908`)

Expand Down Expand Up @@ -587,13 +587,13 @@ Notable changes
- You can now write preloaded and potentially modified data with
:func:`mne_bids.write_raw_bids` by passing ``allow_preload=True``. This is
a first step towards supporting derivative files.
- `mne_bids.BIDSPath` now has property getters and setters for all BIDS
- :func:`mne_bids.BIDSPath` now has property getters and setters for all BIDS
entities. What this means is that you can now do things like
``bids_path.subject = '01'`` instead of ``bids_path.update(subject='01')``.
- We now support Deep Brain Stimulation (DBS) data.
- The way we handle anatomical landmarks was greatly revamped to ensure we're
always using the correct coordinate systems. A new function,
`mne_bids.get_anat_landmarks`, helps with extracting fiducial points from
:func:`mne_bids.get_anat_landmarks`, helps with extracting fiducial points from
anatomical scans.
- When creating a BIDS dataset from FIFF files on macOS and Linux, MNE-BIDS
can now optionally generate symbolic links to the original files instead of
Expand Down Expand Up @@ -859,7 +859,7 @@ been cooking for you!

Notable changes
~~~~~~~~~~~~~~~
- We introduce `mne_bids.BIDSPath`, a new class for all BIDS file and folder
- We introduce :func:`mne_bids.BIDSPath`, a new class for all BIDS file and folder
operations. All functions in MNE-BIDS that previously accepted filenames
and folder locations (e.g. ``bids_root``) have been updated to work with
``BIDSPath``. Others have been removed.
Expand Down Expand Up @@ -956,7 +956,7 @@ Bug fixes
API changes
^^^^^^^^^^^

In the transition to using `mne_bids.BIDSPath`, the following functions have been updated:
In the transition to using :func:`mne_bids.BIDSPath`, the following functions have been updated:

- :func:`mne_bids.write_anat` now accepts a :class:`mne_bids.BIDSPath` instead of entities as keyword arguments, by `Adam Li`_ (:gh:`575`)
- In :func:`mne_bids.write_raw_bids`, :func:`mne_bids.read_raw_bids`, and :func:`mne_bids.get_head_mri_trans`, the ``bids_basename`` and ``bids_root`` keyword arguments have been removed. The functions now expect ``bids_path``, an instance of :class:`mne_bids.BIDSPath`, by `Adam Li`_ (:gh:`525`)
Expand Down Expand Up @@ -1110,7 +1110,7 @@ Bug
API
~~~

- :func:`make_dataset_description` is now available from `mne_bids` main namespace, all copyfile functions are available from `mne_bids.copyfiles` namespace, by `Stefan Appelhoff`_ (:gh:`196`)
- :func:`make_dataset_description` is now available from `mne_bids` main namespace, all copyfile functions are available from :func:`mne_bids.copyfiles` namespace, by `Stefan Appelhoff`_ (:gh:`196`)
- Add support for non maxfiltered .fif files, by `Maximilien Chaumon`_ (:gh:`171`)
- Remove support for Neuroscan ``.cnt`` data because its support is no longer planned in BIDS, by `Stefan Appelhoff`_ (:gh:`142`)
- Remove support for Python 2 because it is no longer supported in MNE-Python, by `Teon Brooks`_ (:gh:`141`)
Expand Down
2 changes: 1 addition & 1 deletion examples/bidspath.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
# **data type**, i.e., ``meg`` for MEG data, ``eeg`` and ``ieeg`` for EEG and
# iEEG data, or ``anat`` for anatomical MRI scans. Typically, MNE-BIDS will
# infer the data type of your data automatically, for example when writing data
# using `mne_bids.write_raw_bids`. For the sake of this example, however, we
# using :func:`mne_bids.write_raw_bids`. For the sake of this example, however, we
# are going to specify the data type explicitly.

datatype = "eeg"
Expand Down
2 changes: 1 addition & 1 deletion examples/read_bids_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
#
# We can use MNE-BIDS to print a tree of all
# included files and folders. We pass the ``max_depth`` parameter to
# `mne_bids.print_dir_tree` to the output to four levels of folders, for
# :func:`mne_bids.print_dir_tree` to the output to four levels of folders, for
# better readability in this example.

print_dir_tree(bids_root, max_depth=4)
Expand Down
2 changes: 1 addition & 1 deletion examples/update_bids_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
#
# We can use MNE-BIDS to print a tree of all
# included files and folders. We pass the ``max_depth`` parameter to
# `mne_bids.print_dir_tree` to the output to three levels of folders, for
# :func:`mne_bids.print_dir_tree` to the output to three levels of folders, for
# better readability in this example.

print_dir_tree(bids_root, max_depth=3)
Expand Down
9 changes: 9 additions & 0 deletions mne_bids/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ def pytest_configure(config):
config.addinivalue_line("usefixtures", "monkeypatch_mne")


@pytest.fixture(autouse=True)
def close_all():
"""Close all figures after each test."""
yield
import matplotlib.pyplot as plt

plt.close("all")


@pytest.fixture(scope="session")
def monkeypatch_mne():
"""Monkeypatch MNE to ensure we have download=False everywhere in tests."""
Expand Down
8 changes: 4 additions & 4 deletions mne_bids/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ def update(self, *, check=None, **kwargs):
If a boolean, controls whether to enforce BIDS conformity. This
will set the ``.check`` attribute accordingly. If ``None``, rely on
the existing ``.check`` attribute instead, which is set upon
`mne_bids.BIDSPath` instantiation. Defaults to ``None``.
:class:`mne_bids.BIDSPath` instantiation. Defaults to ``None``.
**kwargs : dict
It can contain updates for valid BIDSPath entities:
'subject', 'session', 'task', 'acquisition', 'processing', 'run',
Expand Down Expand Up @@ -1018,7 +1018,7 @@ def match(self, ignore_json=True, check=False):
check : bool
If ``True``, only returns paths that conform to BIDS. If ``False``
(default), the ``.check`` attribute of the returned
`mne_bids.BIDSPath` object will be set to ``True`` for paths that
:class:`mne_bids.BIDSPath` object will be set to ``True`` for paths that
do conform to BIDS, and to ``False`` for those that don't.
Returns
Expand Down Expand Up @@ -2382,7 +2382,7 @@ def find_matching_paths(
check : bool
If ``True``, only returns paths that conform to BIDS. If ``False``
(default), the ``.check`` attribute of the returned
`mne_bids.BIDSPath` object will be set to ``True`` for paths that
:class:`mne_bids.BIDSPath` object will be set to ``True`` for paths that
do conform to BIDS, and to ``False`` for those that don't.
Returns
Expand Down Expand Up @@ -2459,7 +2459,7 @@ def _fnames_to_bidspaths(fnames, root, check=False):
check : bool
If ``True``, only returns paths that conform to BIDS. If ``False``
(default), the ``.check`` attribute of the returned
`mne_bids.BIDSPath` object will be set to ``True`` for paths that
:class:`mne_bids.BIDSPath` object will be set to ``True`` for paths that
do conform to BIDS, and to ``False`` for those that don't.
Returns
Expand Down
3 changes: 2 additions & 1 deletion mne_bids/tests/data/tiny_bids/code/make_tiny_bids_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

# %%
import json
from datetime import date
from pathlib import Path

import mne
Expand Down Expand Up @@ -45,7 +46,7 @@
"last_name": "Musterperson",
"first_name": "Maxi",
"middle_name": "Luka",
"birthday": (1970, 10, 20),
"birthday": date(1970, 10, 20),
"sex": 2,
"hand": 3,
}
Expand Down
5 changes: 1 addition & 4 deletions mne_bids/tests/test_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -827,12 +827,9 @@ def test_handle_chpi_reading(tmp_path):

with (
pytest.warns(RuntimeWarning, match="Defaulting to .* mne.Raw object"),
pytest.warns(
RuntimeWarning, match="This file contains raw Internal Active Shielding"
),
pytest.warns(RuntimeWarning, match="The unit for channel"),
):
raw_read = read_raw_bids(bids_path)
raw_read = read_raw_bids(bids_path, extra_params=dict(allow_maxshield="yes"))

# cHPI "off" according to sidecar, but present in the data
meg_json_data_chpi_mismatch = meg_json_data.copy()
Expand Down
14 changes: 11 additions & 3 deletions mne_bids/tests/test_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import shutil as sh
import sys
import warnings
from datetime import datetime, timedelta, timezone
from datetime import date, datetime, timedelta, timezone
from glob import glob
from pathlib import Path

Expand Down Expand Up @@ -102,6 +102,8 @@

def _wrap_read_raw(read_raw):
def fn(fname, *args, **kwargs):
if str(fname).endswith(".mff") and check_version("mne", "1.8"):
kwargs["events_as_annotations"] = True
raw = read_raw(fname, *args, **kwargs)
raw.info["line_freq"] = 60
return raw
Expand Down Expand Up @@ -222,9 +224,12 @@ def test_write_participants(_bids_validate, tmp_path):

# add fake participants data
raw.set_meas_date(datetime(year=1994, month=1, day=26, tzinfo=timezone.utc))
birthday = (1993, 1, 26)
if check_version("mne", "1.8"):
birthday = date(*birthday)
raw.info["subject_info"] = {
"his_id": subject_id2,
"birthday": (1993, 1, 26),
"birthday": birthday,
"sex": 1,
"hand": 2,
}
Expand Down Expand Up @@ -707,9 +712,12 @@ def test_fif(_bids_validate, tmp_path):
# data
# change the gender but don't force overwrite.
raw = _read_raw_fif(raw_fname)
birthday = (1994, 1, 26)
if check_version("mne", "1.8"):
birthday = date(*birthday)
raw.info["subject_info"] = {
"his_id": subject_id2,
"birthday": (1994, 1, 26),
"birthday": birthday,
"sex": 2,
"hand": 1,
}
Expand Down
8 changes: 5 additions & 3 deletions mne_bids/write.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import sys
import warnings
from collections import OrderedDict, defaultdict
from datetime import datetime, timedelta, timezone
from datetime import date, datetime, timedelta, timezone
from pathlib import Path

import mne
Expand Down Expand Up @@ -456,12 +456,14 @@ def _participants_tsv(raw, subject_id, fname, overwrite=False):

# determine the age of the participant
age = subject_info.get("birthday", None)
if isinstance(age, tuple): # can be removed once MNE >= 1.8 is required
age = date(*age)
meas_date = raw.info.get("meas_date", None)
if isinstance(meas_date, (tuple, list, np.ndarray)):
meas_date = meas_date[0]

if meas_date is not None and age is not None:
bday = datetime(age[0], age[1], age[2], tzinfo=timezone.utc)
bday = datetime(age.year, age.month, age.day, tzinfo=timezone.utc)
if isinstance(meas_date, datetime):
meas_datetime = meas_date
else:
Expand Down Expand Up @@ -1408,7 +1410,7 @@ def write_raw_bids(
already loaded from disk unless ``allow_preload`` is explicitly set
to ``True``. See warning for the ``allow_preload`` parameter.
bids_path : BIDSPath
The file to write. The `mne_bids.BIDSPath` instance passed here
The file to write. The :class:`mne_bids.BIDSPath` instance passed here
**must** have the ``subject``, ``task``, and ``root`` attributes set.
If the ``datatype`` attribute is not set, it will be inferred from the
recording data type found in ``raw``. In case of multiple data types,
Expand Down
7 changes: 5 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@ full = [
]

# Dependencies for running the test infrastructure
test = ["mne_bids[full]", "pytest", "pytest-cov", "pytest-sugar", "ruff"]
test = ["mne_bids[full]", "pytest >= 8", "pytest-cov", "pytest-sugar", "ruff"]

# Dependencies for building the documentation
doc = [
"nilearn",
"sphinx",
# TODO: Remove pin once https://github.com/sphinx-doc/sphinx/issues/12589 is fixed
"sphinx!=7.4.6,!=7.4.5,!=7.4.4,!=7.4.3,!=7.4.2,!=7.4.1,!=7.4.0",
"sphinx_gallery",
"sphinx-copybutton",
"pydata-sphinx-theme",
Expand Down Expand Up @@ -148,4 +149,6 @@ filterwarnings = [
# old MNE _fake_click
"ignore:The .*_event function was deprecated in Matplotlib.*:",
"ignore:datetime\\.datetime\\.utcfromtimestamp.* is deprecated and scheduled for removal in a future version.*:DeprecationWarning",
# matplotlib
"ignore:Figure.*is non-interactive.*cannot be shown:UserWarning",
]

0 comments on commit af12bc4

Please sign in to comment.