SyntaxError Using subprocess in MorphoSourceImportV2 Module

Hello Slicer Community,

I’m developing a module, MorphoSourceImportV2, for 3D Slicer to download media from MorphoSource in the background. However, I’ve encountered a SyntaxError when trying to use the subprocess module within Slicer.

File “/Applications/Slicer.app/Contents/bin/…/lib/Python/lib/python3.9/site.py”, line 178
file=sys.stderr)
^
SyntaxError: invalid syntax

This error arises when I attempt to run a subprocess for downloading media files.

Module Repository: The module’s code is available in my forked repository: MorphoSourceImportV2 on GitHub.

I would greatly appreciate any insights or suggestions you might have on resolving this issue. If anyone has experience with using subprocess in Slicer or has encountered similar problems, your guidance would be invaluable.

Thank you in advance for your help!

I bit more context to this question:

These downloads are long (multiple GBs per file), and can be multiple dataset. We do not want the Slicer UI to be non-responsive during downloads, which should happen in the background.

Any suggestions to do this would be appreciated.

Doing the downloads in a subprocess makes sense. You could look at how the DICOMProcess code handles this. Basically a QProcess is started as the process downloads data the main Slicer process gets signals that tell it when to read the results. The ParallelProcessing extension code works the same way and might be easier to read.

Thank you, Steve! I’ll try these approaches.

I’ve successfully used subprocess.Popen to run an external Python script (download_script.py) from within a Slicer module, and it’s working great for downloading data. However, I have a couple of questions regarding best practices for script placement and specifying the Python interpreter in Slicer:

  1. Script Location: Currently, download_script.py is located in the same folder as the module file. I’ve specified its file path explicitly in the code. Is this the recommended location for such scripts, or should they be placed elsewhere? Additionally, is there a way to reference the script’s location relative to the module file, to make the module more portable?
  2. Python Interpreter Path: For the Python interpreter, I’ve used a hard-coded path to Slicer’s Python (/Applications/Slicer.app/Contents/bin/PythonSlicer). However, I’m wondering if there’s a more dynamic way to reference the interpreter, perhaps using sys.executable or a similar approach. This would be particularly useful for ensuring the module’s compatibility across different systems and Slicer installations.

Steve, thanks again for your help! I look forward to your response. It would be helpful not only for refining my current module but also for guiding best practices for the Slicer developer community.

I think supplementary files for modules go under Resources/ folder of the module hierarchy.

slicer.util.modulePath('MorphoSourceImportV2')
returns the path of python script for your module. If you put the download_script.py within the Resources folder then you can paste these together to form the correct path that will be portable

os.getcwd()
returns the path of where slicer install tree is (i.e., working directory for the python console)
'C:\\Users\\amaga\\AppData\\Local\\slicer.org\\Slicer 5.4.0'

so, the path of the Python interpreter is bin/PythonSlicer under this tree.

os.path.exists("bin/PythonSlicer.exe")
True

@othomas2 I suggest you change from using subprocess.Popen and instead use QProcess for use within Slicer. The reason is that QProcess integrates with the Qt event loop for the application, so that instead of relying on. timer, you can be notified of events from the process as they happen. This is a cleaner approach and in general it is more efficient and provides a smoother user experience.

I agree with @muratmaga 's suggestions about using the Resources directory and locating it relative to the module path for consistency across os platforms. Do avoid using .exe as that is windows specific.