How to import Qt in Python scripted CLI module?

Is it possible to import Qt inside a Python scripted CLI module? I want to display an error message to tell the user to modify the input parameters. When I try to import qt I get the following error:

Traceback (most recent call last):
  File "/home/ben/projects/SlicerCBM/SlicerFreeSurferCommands/FreeSurferSynthStripSkullStrip/FreeSurferSynthStripSkullStrip.py", line 4, in <module>
    import qt
  File "/opt/slicer/Slicer-5.2.2-linux-amd64/bin/Python/qt/__init__.py", line 19, in <module>
    from PythonQt.private import QObject
ModuleNotFoundError: No module named 'PythonQt'

I also tried import tkinter:

Traceback (most recent call last):
  File "/home/ben/projects/SlicerCBM/SlicerFreeSurferCommands/FreeSurferSynthStripSkullStrip/FreeSurferSynthStripSkullStrip.py", line 130, in <module>
    import tkinter
  File "/opt/slicer/Slicer-5.2.2-linux-amd64/lib/Python/lib/python3.9/tkinter/__init__.py", line 37, in <module>
    import _tkinter # If this fails your Python may not be configured for Tk
ModuleNotFoundError: No module named '_tkinter'

This seems like the simplest way to do it:

    import slicer.util
    slicer.util.errorDisplay("Something wrong.")

but it also fails

Traceback (most recent call last):
  File "/home/ben/projects/SlicerCBM/SlicerFreeSurferCommands/FreeSurferSynthStripSkullStrip/FreeSurferSynthStripSkullStrip.py", line 129, in <module>
    slicer.util.errorDisplay("Something wrong.")
  File "/opt/slicer/Slicer-5.2.2-linux-amd64/bin/Python/slicer/util.py", line 2668, in errorDisplay
    import qt, logging
  File "/opt/slicer/Slicer-5.2.2-linux-amd64/bin/Python/qt/__init__.py", line 19, in <module>
    from PythonQt.private import QObject
ModuleNotFoundError: No module named 'PythonQt'

As an aside, are the slicer.util functions in general intended to be also used from CLI modules or do they only work in scripted modules?

Python scripted CLI modules must never display any GUI. The user interface is generated automatically by Slicer. The algorithm must not be blocked by waiting for any user inputs. Progress information can be provided to the application by printing XML elements on the process output.

You can implement interactive GUI in Python in Python scripted loadable modules. A Python scripted loadable module can also call CLI modules (implemented in C++ or Python), so if you already have a CLI module then you can add a scripted loadable module if you need more customized, interactive GUI.

That makes a lot of sense.

Is there an example of this somewhere?

All I want to do is display an error if the user doesn’t specify the correct input. I was using argparse like this:

    parser.add_argument('-i', '--image', required=True,
                        help='Input image to skullstrip.')

but it gives very noisy output:

FreeSurfer SynthStrip Skull Strip standard error:

usage: FreeSurferSynthStripSkullStrip.py [-h] -i IMAGE [-o OUT] [-m MASK]
                                         [-g | --gpu | --no-gpu] [-b BORDER]
                                         [--nocsf | --no-nocsf]
FreeSurferSynthStripSkullStrip.py: error: the following arguments are required: -i/--image

FreeSurfer SynthStrip Skull Strip standard output:

/home/ben/projects/SlicerCBM/SlicerFreeSurferCommands/FreeSurferSynthStripSkullStrip/FreeSurferSynthStripSkullStrip.py

The other alternative, which is more flexible is this:

    if not args.out and not args.mask:
        print("Error: User must request output Stripped Volume, Mask Volume, or both.")
        sys.exit(1)

which gives the following output:

FreeSurfer SynthStrip Skull Strip standard output:

/home/ben/projects/SlicerCBM/SlicerFreeSurferCommands/FreeSurferSynthStripSkullStrip/FreeSurferSynthStripSkullStrip.py
Error: User must request output Stripped Volume, Mask Volume, or both.

Is there a recommended way to do this? In C++ CLI modules the PARSE_ARGS macro seems to take care of this. By the way, where is that macro defined? I tried to search for it but couldn’t find it.

If you print something on the error output and the process returns with an error then the error message is displayed in the CLI module GUI:

Progress reporting is described here: Documentation/Nightly/Developers/SlicerExecutionModel - Slicer Wiki

This is autogenerated from the XML description of the CLI, so you can find it in the build tree for the module.

1 Like