Skip to content

Commit 4d3e368

Browse files
committed
Added file-locking to interface
Now, the interface is thread-safe using lockfile. It is included in documentation, and also a warning is issued when the module is not available or could not be imported.
1 parent 3b23d82 commit 4d3e368

File tree

1 file changed

+28
-13
lines changed

1 file changed

+28
-13
lines changed

nipype/algorithms/misc.py

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@
2626
import itertools
2727
import scipy.stats as stats
2828

29-
from .. import logging
29+
from nipype import logging
3030

31-
from ..interfaces.base import (BaseInterface, traits, TraitedSpec, File,
31+
from nipype.interfaces.base import (BaseInterface, traits, TraitedSpec, File,
3232
InputMultiPath, OutputMultiPath,
3333
BaseInterfaceInputSpec, isdefined,
3434
DynamicTraitedSpec )
35-
from ..utils.filemanip import fname_presuffix, split_filename
35+
from nipype.utils.filemanip import fname_presuffix, split_filename
3636
iflogger = logging.getLogger('interface')
3737

3838

@@ -1168,15 +1168,12 @@ class AddCSVRowOutputSpec(TraitedSpec):
11681168
class AddCSVRow(BaseInterface):
11691169
"""Simple interface to add an extra row to a csv file
11701170
1171-
.. warning::
1171+
.. note:: Requires `pandas <http://pandas.pydata.org/>`_
11721172
1173-
This interface is not thread-safe in multi-proc mode when
1174-
writing the output file.
1175-
1176-
1177-
.. note::
1178-
1179-
Requires pandas - http://pandas.pydata.org/
1173+
.. warning:: Multi-platform thread-safe execution is possible with
1174+
`lockfile <https://pythonhosted.org/lockfile/lockfile.html>`_. Please recall that (1)
1175+
this module is alpha software; and (2) it should be installed for thread-safe writing.
1176+
If lockfile is not installed, then the interface is not thread-safe.
11801177
11811178
11821179
Example
@@ -1193,10 +1190,10 @@ class AddCSVRow(BaseInterface):
11931190
"""
11941191
input_spec = AddCSVRowInputSpec
11951192
output_spec = AddCSVRowOutputSpec
1193+
_have_lock = False
1194+
_lock = None
11961195

11971196
def __init__(self, infields=None, force_run=True, **kwargs):
1198-
import warnings
1199-
warnings.warn('AddCSVRow is not thread-safe in multi-processor execution')
12001197
super(AddCSVRow, self).__init__(**kwargs)
12011198
undefined_traits = {}
12021199
self._infields = infields
@@ -1217,6 +1214,15 @@ def _run_interface(self, runtime):
12171214
except ImportError:
12181215
raise ImportError('This interface requires pandas (http://pandas.pydata.org/) to run.')
12191216

1217+
try:
1218+
import lockfile as pl
1219+
self._have_lock = True
1220+
except ImportError:
1221+
import warnings
1222+
warnings.warn(('Python module lockfile was not found: AddCSVRow will not be thread-safe '
1223+
'in multi-processor execution'))
1224+
1225+
12201226

12211227
input_dict = {}
12221228

@@ -1230,13 +1236,22 @@ def _run_interface(self, runtime):
12301236

12311237
df = pd.DataFrame([input_dict])
12321238

1239+
if self._have_lock:
1240+
self._lock = pl.FileLock(self.inputs.in_file)
1241+
1242+
# Acquire lock
1243+
self._lock.acquire()
1244+
12331245
if op.exists(self.inputs.in_file):
12341246
formerdf = pd.read_csv(self.inputs.in_file, index_col=0)
12351247
df = pd.concat( [formerdf, df], ignore_index=True )
12361248

12371249
with open(self.inputs.in_file, 'w') as f:
12381250
df.to_csv(f)
12391251

1252+
if self._have_lock:
1253+
self._lock.release()
1254+
12401255
return runtime
12411256

12421257
def _list_outputs(self):

0 commit comments

Comments
 (0)