Python -called from subprocess- is unable to import SimpleITK

Hello everybody,

I want to call a python module from Slicer, but I need to call it through the subprocess module and not directly from Slicer’s Python environment. This is because my module uses scipy, which is not available in Slicer’s Pyhton (my module also depends on SimpleITK, which also brings a problem as you may see below).

I have tried to call my module using subprocess.check_call but it fails as scipy is not avaiable. In fact, a single call to import scipy fails:

>>> import subprocess
>>> python_path = 'C:/Users/abertelsen/AppData/Local/Continuum/Anaconda2/python.exe'
>>> subprocess.check_call([python_path, '-c', 'import scipy'])
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Program Files\Slicer 4.8.1\lib\Python\Lib\", line 219, in check_output
    raise CalledProcessError(retcode, cmd, output=output)
CalledProcessError: Command '['C:/Users/abertelsen/AppData/Local/Continuum/Anaconda2/python.exe', '-c', 'import scipy']' returned non-zero exit status 1

I though that the problem may be related to the environment variables, so I added the -E option to python -which forces Python to ignore all environment variables that begin with ‘PYTHON*’- and it seemed to work:

>>> subprocess.check_call([python_path, '-E', '-c', 'import scipy'])

And now comes the ‘funny’ part: adding the -E option prevents the import of SimpleITK

>>> subprocess.check_call([python_path, '-E', '-c', 'import SimpleITK'])
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Program Files\Slicer 4.8.1\lib\Python\Lib\", line 186, in check_call
    raise CalledProcessError(retcode, cmd)
CalledProcessError: Command '['C:/Users/abertelsen/AppData/Local/Continuum/Anaconda2/python.exe', '-E', '-c', 'import SimpleITK']' returned non-zero exit status -1073740777

…but removing the -E option solves the problem

>>> subprocess.check_call([python_path, '-c', 'import SimpleITK'])

Therefore, if I add the -E option I am unable to import SimpleITK and, if I remove it, I become unable to import scipy. In both cases, I am unable to run my script from Slicer :frowning:

My Python environment is Anaconda2 (with Python 2.7.13, which is the same Python version that Slicer 4.8.1 uses). I do not get the same problem calling the commands above from the Anaconda Prompt: in fact, all cases above work when called from there.

Some info on my environment:

  • Slicer 4.8.1 (with Python 2.7.13)
  • Anaconda2 4.4.0 64-bits (with Python 2.7.13)
  • Windows 10 (64 bits)

Any help would be greatly appreciated!

Best wishes,
Álvaro B.

PS I have noticed that Slicer’s Python has been compiled with MSC v.1800, whereas Anaconda’s Python has been compiled with MSC v.1500. Do you believe that the problem may be related to the compiler? I doubt it, but I wanted to add this point.

You can use slicer.util.startupEnvironment() to get an unmodified system environment. See details in this post: Subprocess call in Python interpreter results in memory corruption

Using slicer.util.startupEnvironment still produces an error

subprocess.check_output([python_path, '-c', 'import SimpleITK'], env=slicer.util.startupEnvironment())

Traceback (most recent call last): File "<console>", line 1, in <module> File "C:\Program Files\Slicer 4.8.1\lib\Python\Lib\", line 212, in check_output process = Popen(stdout=PIPE, *popenargs, **kwargs) File "C:\Program Files\Slicer 4.8.1\lib\Python\Lib\", line 390, in __init__ errread, errwrite) File "C:\Program Files\Slicer 4.8.1\lib\Python\Lib\", line 640, in _execute_child startupinfo) TypeError: environment can only contain strings

I get the same error calling Python with or without the -E option.

If you installed SimpleITK with pip rather than conda, then it might rely on something being in PATH.

A hacky quick-fix for the TypeError might be passing a modified environment, env = {str(k): str(v) for k,v in slicer.util.startupEnvironment().items()}.

I just see now that you use Slicer-4.8.1. This issue has been fixed in recent Slicer-4.9.x versions.

Calling subprocess.check_call using the modified env did the trick. Thank you Andras and Isaiah for your replies!

Best wishes,
Álvaro B.

Forced conversion to string was implemented in nightly (Slicer-4.9.x) version several months ago. So, any recent nightly builds should work as is.