Repository: nipy/nipype

Issue:
TypeError: environment can only contain strings
### Summary
I'm working on an image processing task with nipype, and I got the following problem
### Actual behavior

### Expected behavior

### How to replicate the behavior

### Script/Workflow details

```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\study\project\3D cnn\3DUnetCNN-master\brats\preprocess.py", line 155, in convert_brats_data
    no_bias_correction_modalities=no_bias_correction_modalities)
  File "D:\study\project\3D cnn\3DUnetCNN-master\brats\preprocess.py", line 124, in convert_brats_folder
    normalize_image(image_file, out_file, bias_correction=perform_bias_correction)
  File "D:\study\project\3D cnn\3DUnetCNN-master\brats\preprocess.py", line 112, in normalize_image
    correct_bias(in_file, out_file)
  File "D:\study\project\3D cnn\3DUnetCNN-master\brats\preprocess.py", line 70, in correct_bias
    done = correct.run()
  File "D:\softwares\Annoconda3\lib\site-packages\nipype\interfaces\base\core.py", line 498, in run
    version=self.version)
  File "D:\softwares\Annoconda3\lib\site-packages\nipype\interfaces\ants\base.py", line 125, in version
    return Info.version()
  File "D:\softwares\Annoconda3\lib\site-packages\nipype\interfaces\base\core.py", line 1283, in version
    terminal_output='allatonce').run()
  File "D:\softwares\Annoconda3\lib\site-packages\nipype\interfaces\base\core.py", line 516, in run
    runtime = self._run_interface(runtime)
  File "D:\softwares\Annoconda3\lib\site-packages\nipype\interfaces\base\core.py", line 1020, in _run_interface
    runtime = run_command(runtime, output=self.terminal_output)
  File "D:\softwares\Annoconda3\lib\site-packages\nipype\interfaces\base\core.py", line 750, in run_command
    close_fds=False,
  File "D:\softwares\Annoconda3\lib\subprocess.py", line 709, in __init__
    restore_signals, start_new_session)
  File "D:\softwares\Annoconda3\lib\subprocess.py", line 997, in _execute_child
    startupinfo)
TypeError: environment can only contain strings
```

here are the codes that produced the error:

```
        def _execute_child(self, args, executable, preexec_fn, close_fds,
                           pass_fds, cwd, env,
                           startupinfo, creationflags, shell,
                           p2cread, p2cwrite,
                           c2pread, c2pwrite,
                           errread, errwrite,
                           unused_restore_signals, unused_start_new_session):
            """Execute program (MS Windows version)"""

            assert not pass_fds, "pass_fds not supported on Windows."

            if not isinstance(args, str):
                args = list2cmdline(args)

            # Process startup details
            if startupinfo is None:
                startupinfo = STARTUPINFO()
            if -1 not in (p2cread, c2pwrite, errwrite):
                startupinfo.dwFlags |= _winapi.STARTF_USESTDHANDLES
                startupinfo.hStdInput = p2cread
                startupinfo.hStdOutput = c2pwrite
                startupinfo.hStdError = errwrite

            if shell:
                startupinfo.dwFlags |= _winapi.STARTF_USESHOWWINDOW
                startupinfo.wShowWindow = _winapi.SW_HIDE
                comspec = os.environ.get("COMSPEC", "cmd.exe")
                args = '{} /c "{}"'.format (comspec, args)

            # Start the process
            try:
                hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
                                         # no special security
                                         None, None,
                                         int(not close_fds),
                                         creationflags,
                                         env,
                                         os.fspath(cwd) if cwd is not None else None,
                                         startupinfo)
```

### Platform details:

```
{'pkg_path': 'D:\\softwares\\Annoconda3\\lib\\site-packages\\nipype',
 'commit_source': 'installation',
 'commit_hash': 'bded0d02',
 'nipype_version': '1.0.1',
 'sys_version': '3.6.3 |Anaconda custom (64-bit)| (default, Oct 15 2017, 03:27:45) [MSC v.1900 64 bit (AMD64)]',
 'sys_executable': 'D:\\softwares\\Annoconda3\\python.exe',
 'sys_platform': 'win32',
 'numpy_version': '1.13.3',
 'scipy_version': '0.19.1',
 'networkx_version': '2.0',
 'nibabel_version': '2.2.1',
 'traits_version': '4.6.0'}
1.0.1
```
### Execution environment


can anyone help me with this? any suggestion is appreciated.


Discussion:
So it looks like this may be an incompatibility of [3DUnetCNN](https://github.com/ellisdg/3DUnetCNN) with more recent versions of nipype. Do they provide docker images that pre-package known compatible versions? If not, this may be worth tracking down on their side, and then seeing if there's something we can do here to resolve the issue.
I have exactly the same issue! Can anyone help with this?
I also have the same issue when using SPM interface. Is there any solutions? I'm using win10, and have spm running correctly in matlab. 
Can you share the code producing the issue?
I think maybe this is the issue with popen under win10 environment. There are no such error when I switch to run my code in docker. 
Hi, I also face this problem when I just used the example code.

from nipype.interfaces.dcm2nii import Dcm2niix

converter = Dcm2niix()
converter.inputs.source_dir = 'xxx'
converter.inputs.compression = 5
converter.inputs.output_dir = 'yyy'
 converter.cmdline
 'dcm2niix -b y -z y -5 -x n -t n -m n -o ds005 -s n -v n dicomdir'
converter.run() 


![image](https://user-images.githubusercontent.com/34640207/97916525-50f75200-1d10-11eb-815e-d3fd56a258aa.png)

can anybody solve this?

Thanks


Resolving patch:
diff --git a/nipype/interfaces/base/core.py b/nipype/interfaces/base/core.py
--- a/nipype/interfaces/base/core.py
+++ b/nipype/interfaces/base/core.py
@@ -26,7 +26,7 @@
 from ... import config, logging, LooseVersion
 from ...utils.provenance import write_provenance
 from ...utils.misc import str2bool, rgetcwd
-from ...utils.filemanip import split_filename, which, get_dependencies
+from ...utils.filemanip import split_filename, which, get_dependencies, canonicalize_env
 from ...utils.subprocess import run_command
 
 from ...external.due import due
@@ -778,7 +778,7 @@ def version_from_command(self, flag="-v", cmd=None):
             proc = sp.Popen(
                 " ".join((cmd, flag)),
                 shell=True,
-                env=env,
+                env=canonicalize_env(env),
                 stdout=sp.PIPE,
                 stderr=sp.PIPE,
             )
diff --git a/nipype/utils/filemanip.py b/nipype/utils/filemanip.py
--- a/nipype/utils/filemanip.py
+++ b/nipype/utils/filemanip.py
@@ -26,11 +26,7 @@
 
 fmlogger = logging.getLogger("nipype.utils")
 
-related_filetype_sets = [
-    (".hdr", ".img", ".mat"),
-    (".nii", ".mat"),
-    (".BRIK", ".HEAD"),
-]
+related_filetype_sets = [(".hdr", ".img", ".mat"), (".nii", ".mat"), (".BRIK", ".HEAD")]
 
 
 def _resolve_with_filenotfound(path, **kwargs):
@@ -876,7 +872,7 @@ def get_dependencies(name, environ):
 
 
 def canonicalize_env(env):
-    """Windows requires that environment be dicts with bytes as keys and values
+    """Windows requires that environment be dicts with str as keys and values
     This function converts any unicode entries for Windows only, returning the
     dictionary untouched in other environments.
 
@@ -888,7 +884,7 @@ def canonicalize_env(env):
     Returns
     -------
     env : dict
-        Windows: environment dictionary with bytes keys and values
+        Windows: environment dictionary with str keys and values
         Other: untouched input ``env``
     """
     if os.name != "nt":
@@ -896,10 +892,10 @@ def canonicalize_env(env):
 
     out_env = {}
     for key, val in env.items():
-        if not isinstance(key, bytes):
-            key = key.encode("utf-8")
-        if not isinstance(val, bytes):
-            val = val.encode("utf-8")
+        if not isinstance(key, str):
+            key = key.decode("utf-8")
+        if not isinstance(val, str):
+            val = val.decode("utf-8")
         out_env[key] = val
     return out_env
 


Test patch: