Repository: nipy/nipype

Issue:
Apparent multiprocessing API change in Python 3.7
### Summary

There's a Python 3.7 failure that just began exhibiting on Travis.

```Python
[gw0] [ 99%] FAILED pipeline/plugins/test/test_legacymultiproc_nondaemon.py::test_run_multiproc_nondaemon_true
...
=================================== FAILURES ===================================
______________________ test_run_multiproc_nondaemon_true _______________________
[gw0] linux -- Python 3.7.1 /home/travis/virtualenv/python3.7.1/bin/python
    def test_run_multiproc_nondaemon_true():
        # with nondaemon_flag = True, the execution should succeed
>       result = run_multiproc_nondaemon_with_flag(True)
/home/travis/build/nipy/nipype/nipype/pipeline/plugins/tests/test_legacymultiproc_nondaemon.py:165: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/home/travis/build/nipy/nipype/nipype/pipeline/plugins/tests/test_legacymultiproc_nondaemon.py:132: in run_multiproc_nondaemon_with_flag
    'non_daemon': nondaemon_flag
/home/travis/build/nipy/nipype/nipype/pipeline/engine/workflows.py:579: in run
    runner = plugin_mod(plugin_args=plugin_args)
/home/travis/build/nipy/nipype/nipype/pipeline/plugins/legacymultiproc.py:162: in __init__
    initargs=(self._cwd,)
/opt/python/3.7.1/lib/python3.7/multiprocessing/pool.py:177: in __init__
    self._repopulate_pool()
/opt/python/3.7.1/lib/python3.7/multiprocessing/pool.py:238: in _repopulate_pool
    self._wrap_exception)
/opt/python/3.7.1/lib/python3.7/multiprocessing/pool.py:252: in _repopulate_pool_static
    wrap_exception)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <[AttributeError("'NonDaemonProcess' object has no attribute '_closed'") raised in repr()] NonDaemonProcess object at 0x7fa0ad3d24a8>
group = <multiprocessing.context.ForkContext object at 0x7fa0d7aeda90>
target = <function worker at 0x7fa0af430840>, name = None
args = (<multiprocessing.queues.SimpleQueue object at 0x7fa0ad2afcf8>, <multiprocessing.queues.SimpleQueue object at 0x7fa0ad10d6a0>, <built-in function chdir>, ('/tmp/test_engine_y5eb4eh0',), 10, True)
kwargs = {}
    def __init__(self, group=None, target=None, name=None, args=(), kwargs={},
                 *, daemon=None):
>       assert group is None, 'group argument must be None for now'
E       AssertionError: group argument must be None for now
/opt/python/3.7.1/lib/python3.7/multiprocessing/process.py:74: AssertionError
```

### Platform details:

```
Python: 3.7
INSTALL_DEB_DEPENDECIES=true NIPYPE_EXTRAS="doc,tests,nipy,profiler" CI_SKIP_TEST=1
```
### Execution environment

Travis


Comments:

Patch:
diff --git a/nipype/info.py b/nipype/info.py
index 5efb4282b..936c6b63e 100644
--- a/nipype/info.py
+++ b/nipype/info.py
@@ -108,7 +108,7 @@ DATEUTIL_MIN_VERSION = '2.2'
 PYTEST_MIN_VERSION = '3.0'
 FUTURE_MIN_VERSION = '0.16.0'
 SIMPLEJSON_MIN_VERSION = '3.8.0'
-PROV_VERSION = '1.5.0'
+PROV_VERSION = '1.5.2'
 CLICK_MIN_VERSION = '6.6.0'
 PYDOT_MIN_VERSION = '1.2.3'
 
@@ -139,7 +139,8 @@ REQUIRES = [
     'traits>=%s' % TRAITS_MIN_VERSION,
     'future>=%s' % FUTURE_MIN_VERSION,
     'simplejson>=%s' % SIMPLEJSON_MIN_VERSION,
-    'prov==%s' % PROV_VERSION,
+    'prov>=%s' % PROV_VERSION,
+    'neurdflib',
     'click>=%s' % CLICK_MIN_VERSION,
     'funcsigs',
     'pytest>=%s' % PYTEST_MIN_VERSION,
diff --git a/nipype/interfaces/meshfix.py b/nipype/interfaces/meshfix.py
index 4b9db519a..02a0db403 100644
--- a/nipype/interfaces/meshfix.py
+++ b/nipype/interfaces/meshfix.py
@@ -38,10 +38,10 @@ class MeshFixInputSpec(CommandLineInputSpec):
     dont_clean = traits.Bool(argstr='--no-clean', desc="Don't Clean")
 
     save_as_stl = traits.Bool(
-        xor=['save_as_vmrl', 'save_as_freesurfer_mesh'],
+        xor=['save_as_vrml', 'save_as_freesurfer_mesh'],
         argstr='--stl',
         desc="Result is saved in stereolithographic format (.stl)")
-    save_as_vmrl = traits.Bool(
+    save_as_vrml = traits.Bool(
         argstr='--wrl',
         xor=['save_as_stl', 'save_as_freesurfer_mesh'],
         desc="Result is saved in VRML1.0 format (.wrl)")
@@ -210,7 +210,7 @@ class MeshFix(CommandLine):
         if self.inputs.save_as_stl or self.inputs.output_type == 'stl':
             self.inputs.output_type = 'stl'
             self.inputs.save_as_stl = True
-        if self.inputs.save_as_vmrl or self.inputs.output_type == 'vmrl':
-            self.inputs.output_type = 'vmrl'
-            self.inputs.save_as_vmrl = True
+        if self.inputs.save_as_vrml or self.inputs.output_type == 'vrml':
+            self.inputs.output_type = 'vrml'
+            self.inputs.save_as_vrml = True
         return name + '_fixed.' + self.inputs.output_type
diff --git a/nipype/pipeline/plugins/legacymultiproc.py b/nipype/pipeline/plugins/legacymultiproc.py
index d93e6e77d..dd88a5505 100644
--- a/nipype/pipeline/plugins/legacymultiproc.py
+++ b/nipype/pipeline/plugins/legacymultiproc.py
@@ -11,7 +11,7 @@ from __future__ import (print_function, division, unicode_literals,
 
 # Import packages
 import os
-from multiprocessing import Process, Pool, cpu_count, pool
+from multiprocessing import Pool, cpu_count, pool
 from traceback import format_exception
 import sys
 from logging import INFO
@@ -74,23 +74,23 @@ def run_node(node, updatehash, taskid):
     return result
 
 
-class NonDaemonProcess(Process):
-    """A non-daemon process to support internal multiprocessing.
-    """
-
-    def _get_daemon(self):
-        return False
-
-    def _set_daemon(self, value):
-        pass
-
-    daemon = property(_get_daemon, _set_daemon)
-
-
 class NonDaemonPool(pool.Pool):
     """A process pool with non-daemon processes.
     """
-    Process = NonDaemonProcess
+    def Process(self, *args, **kwds):
+        proc = super(NonDaemonPool, self).Process(*args, **kwds)
+
+        class NonDaemonProcess(proc.__class__):
+            """Monkey-patch process to ensure it is never daemonized"""
+            @property
+            def daemon(self):
+                return False
+
+            @daemon.setter
+            def daemon(self, val):
+                pass
+        proc.__class__ = NonDaemonProcess
+        return proc
 
 
 class LegacyMultiProcPlugin(DistributedPluginBase):
diff --git a/requirements.txt b/requirements.txt
index 5ef00ec98..1d1a4d1f9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,7 +6,8 @@ python-dateutil>=2.2
 nibabel>=2.1.0
 future>=0.16.0
 simplejson>=3.8.0
-prov==1.5.0
+prov>=1.5.2
+neurdflib
 click>=6.6.0
 funcsigs
 configparser


Test patch:
diff --git a/nipype/interfaces/tests/test_auto_MeshFix.py b/nipype/interfaces/tests/test_auto_MeshFix.py
index 3cc1541d6..9f50145ba 100644
--- a/nipype/interfaces/tests/test_auto_MeshFix.py
+++ b/nipype/interfaces/tests/test_auto_MeshFix.py
@@ -67,9 +67,9 @@ def test_MeshFix_inputs():
         ),
         save_as_stl=dict(
             argstr='--stl',
-            xor=['save_as_vmrl', 'save_as_freesurfer_mesh'],
+            xor=['save_as_vrml', 'save_as_freesurfer_mesh'],
         ),
-        save_as_vmrl=dict(
+        save_as_vrml=dict(
             argstr='--wrl',
             xor=['save_as_stl', 'save_as_freesurfer_mesh'],
         ),