Skip to content

Commit 75def8a

Browse files
updating the writing logic
1 parent f14bfd9 commit 75def8a

File tree

4 files changed

+58
-23
lines changed

4 files changed

+58
-23
lines changed

mne_bids/_fileio.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,25 @@
88
import contextlib
99
import os
1010
from contextlib import contextmanager
11+
from contextvars import ContextVar
1112
from pathlib import Path
1213

1314
from mne.utils import _soft_import, warn
1415

1516

17+
def _normalize_lock_path(path):
18+
path = Path(path)
19+
try:
20+
return path.resolve()
21+
except OSError:
22+
return path.absolute()
23+
24+
25+
_LOCKED_PATHS: ContextVar[tuple[Path, ...]] = ContextVar(
26+
"_LOCKED_PATHS", default=tuple()
27+
)
28+
29+
1630
def _get_lock_context(path):
1731
"""Return a context manager that locks ``path`` if possible."""
1832
filelock = _soft_import(
@@ -44,9 +58,20 @@ def _get_lock_context(path):
4458
return lock_context, lock_path, have_lock
4559

4660

61+
def _path_is_locked(path) -> bool:
62+
"""Return True if ``path`` is currently locked via :func:`_file_lock`."""
63+
normalized = _normalize_lock_path(path)
64+
return normalized in _LOCKED_PATHS.get()
65+
66+
4767
@contextmanager
4868
def _open_lock(path, *args, **kwargs):
4969
"""Wrap :func:`mne.utils.config._open_lock` and remove stale ``.lock`` files."""
70+
if _path_is_locked(path):
71+
with open(path, *args, **kwargs) as fid:
72+
yield fid
73+
return
74+
5075
lock_context, lock_path, have_lock = _get_lock_context(path)
5176
try:
5277
with lock_context, open(path, *args, **kwargs) as fid:
@@ -63,10 +88,17 @@ def _open_lock(path, *args, **kwargs):
6388
def _file_lock(path):
6489
"""Acquire a lock on ``path`` without opening the file."""
6590
lock_context, lock_path, have_lock = _get_lock_context(path)
91+
normalized = _normalize_lock_path(path)
92+
token = None
93+
if not _path_is_locked(normalized):
94+
current = _LOCKED_PATHS.get()
95+
token = _LOCKED_PATHS.set(current + (normalized,))
6696
try:
6797
with lock_context:
6898
yield
6999
finally:
100+
if token is not None:
101+
_LOCKED_PATHS.reset(token)
70102
if have_lock and lock_path.exists():
71103
try:
72104
lock_path.unlink()

mne_bids/tsv_handler.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import numpy as np
1010

11-
from mne_bids._fileio import _open_lock
11+
from mne_bids._fileio import _open_lock, _path_is_locked
1212

1313

1414
def _combine_rows(data1, data2, drop_column=None):
@@ -188,9 +188,14 @@ def _to_tsv(data, fname):
188188
n_rows = len(data[list(data.keys())[0]])
189189
output = _tsv_to_str(data, n_rows)
190190

191-
with _open_lock(fname, "w", encoding="utf-8-sig") as f:
192-
f.write(output)
193-
f.write("\n")
191+
if _path_is_locked(fname):
192+
with open(fname, "w", encoding="utf-8-sig") as f:
193+
f.write(output)
194+
f.write("\n")
195+
else:
196+
with _open_lock(fname, "w", encoding="utf-8-sig") as f:
197+
f.write(output)
198+
f.write("\n")
194199

195200

196201
def _tsv_to_str(data, rows=5):

mne_bids/utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,21 @@ def _write_tsv(fname, dictionary, overwrite=False, verbose=None):
255255
logger.info(f"Writing '{fname}'...")
256256

257257

258+
def _write_tsv_locked(fname: Path | str, data) -> None:
259+
"""Write TSV data while the caller holds the file lock."""
260+
fname = Path(fname)
261+
columns = list(data.keys())
262+
n_rows = len(data[columns[0]]) if columns else 0
263+
lines = ["\t".join(columns)]
264+
for row_idx in range(n_rows):
265+
lines.append("\t".join(str(data[col][row_idx]) for col in columns))
266+
267+
fname.parent.mkdir(parents=True, exist_ok=True)
268+
with open(fname, "w", encoding="utf-8-sig") as fid:
269+
fid.write("\n".join(lines))
270+
fid.write("\n")
271+
272+
258273
def _write_text(fname, text, overwrite=False):
259274
"""Write text to a file."""
260275
if fname.exists() and not overwrite:

mne_bids/write.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -97,23 +97,6 @@
9797
_BTI_SUFFIX_CACHE: dict[str | None, bool] = {}
9898

9999

100-
def _write_tsv_locked(fname: Path | str, data: OrderedDict) -> None:
101-
"""Write TSV data while the caller holds the file lock."""
102-
fname = Path(fname)
103-
columns = list(data.keys())
104-
n_rows = len(data[columns[0]]) if columns else 0
105-
lines = ["\t".join(columns)]
106-
for row_idx in range(n_rows):
107-
lines.append("\t".join(str(data[col][row_idx]) for col in columns))
108-
109-
fname.parent.mkdir(parents=True, exist_ok=True)
110-
with open(fname, "w", encoding="utf-8-sig") as fid:
111-
fid.write("\n".join(lines))
112-
fid.write("\n")
113-
114-
logger.info(f"Writing '{fname}'...")
115-
116-
117100
def _is_numeric(n):
118101
return isinstance(n, np.integer | np.floating | int | float)
119102

@@ -643,7 +626,7 @@ def _participants_tsv(raw, subject_id, fname, overwrite=False):
643626
# otherwise add the new data as new row
644627
data = _combine_rows(orig_data, data, "participant_id")
645628

646-
_write_tsv_locked(fname, data)
629+
_write_tsv(fname, data, overwrite=True)
647630

648631

649632
def _participants_json(fname, overwrite=False):
@@ -793,7 +776,7 @@ def _scans_tsv(raw, raw_fname, fname, keep_source, overwrite=False):
793776
# otherwise add the new data
794777
data = _combine_rows(orig_data, data, "filename")
795778

796-
_write_tsv_locked(fname, data)
779+
_write_tsv(fname, data, overwrite=True)
797780

798781

799782
def _load_image(image, name="image"):

0 commit comments

Comments
 (0)