Thread for uploading data

Thanks for great SDK and python support.

I am using python and Slicer to upload dicom file to my server using requests.post. My dicom size about 20MB and it takes 1 mins to upload it to server.

During uploading process, the application only runs one thread, so I cannot do other tasks (GUI blocked). Could we create another thread for data uploading and run it on other thread, instead of main thread (GUI)? Do we have any example for the task? Thanks

1 Like

Probably the easiest is to save the data to a file and then use subprocess.run or QProcess to execute a little script that does the upload (you can execute it with PythonSlicer which will be in your path and can run the same python scripts (non-gui) as you would inside slicer).

Are you connecting to a dicomweb server using dicomweb_client or directly via requests?

1 Like

I just directly use request function in python. My data is dump to file and write to buffer to send to a web-service.

My function such as

def send_data():
   with open(path_to_dcm, 'rb') as file:
        file_read = file.read()
        base64_encode = base64.encodebytes(file_read)         
        multipart_form_data = {
              'file': (path_to_dcm, base64_encode, 'dicom')
          }
        try:
            json_results = requests.post(my_url,
                                    files=multipart_form_data)
            return json_results.json()
        except:
            pass

The send_data is called when I click the Send button such as

       self.sendButton = qt.QPushButton("Send")
       self.sendButton.connect("clicked()", self.onSend)

def onSend(self):
    send_data()

Could you give an example how to do subprocess.run or QProcess?

Here’s an example with subprocess to run a job:

Also, coincidentally, I’m working on another example for the SlicerMorph project that maybe be closer to your use case. I hope to publish it soon.

1 Like

Here’s a more elaborate set of code for doing this sort of thing (new, so use with care). It you look at the self test you can see what the interface looks like.

1 Like

Hi Steven, I’ve been looking into your project and have some questions:

How can a process modify the GUI written in ScriptedLoadableModuleWidget inherited class ?
If I put a time.sleep(4) in your processing Input code, the GUI is freeze and unable to access or click.

In case I want to use multi-threading to handle the send to server, I got unexpected issue like when I click in the button and the send to server thread does not working at all. Is there any modules with multi-threading code that I can learn from ?

Thanks you very much

If you want to give a chance for GUI updates while you are doing processing then you need to call slicer.app.processEvents(), not just a sleep.

As you probably know, due to the global interpreter lock, there is no parallel execution of Python code within one interpreter, even if you start multiple threads. For IO operations, asynchronous IO might help, but I don’t know if anyone has figured out how to use that in Slicer.

A simpler solution is to start a separate process for background operations. Fortunately, Slicer already has a very simple solution for this: scripted CLI modules, which are Python scripts that are executed in the background, in a new Python interpreter. If you have a Python script that uploads an input image to a server then all you need to run it in the background in Slicer is to create a simple XML file that describes inputs and outputs of your script - see a complete example here. The XML file allows Slicer to recognize the script as a CLI module, and CLI modules are run in the background by default.

If you start multiple CLI modules in parallel then Slicer puts them in a queue and runs them one after the other.

1 Like

Thanks you very much for your answers.
The example link you provided above seems not working to me
Anyway, I found some useful reference in this github link

However, how can I add this CLI modules to my Slicer


Screenshot from 2020-03-22 20-50-45
This seems not working at all ? Seems like I missed some steps ? Can you show me some instruction into this ?
Again, thank you very much for your help.

I confirm that the module that I linked works well with recent Slicer-4.11 versions. If you have any problems running it then describe what steps you performed, what you expected to happen, and what happened instead.

1 Like

So these are steps that I followed:

  • Clone the git project from here
  • Add the modules inside Slicer: Application Settings → Modules → Add → SlicerRadiomicsCLI
  • Run some experiment code:

parameters = {}
res = slicer.cli.runSync(slicer.modules.SlicerRadiomicsCLI, None, parameters)
print(res)
pass

So are there anything need to be additionally performed ? The version I used is Slicer 4.11 (I think my Slicer is not nightly version since I downloaded the binary in the main page)

The way I want it to work is I’m able to access slicer.modules.SlicerRadiomicsCLI CLI from the scripted code python that I wrote.

OK, what you do will work, just use the example that I provided above: https://github.com/lassoan/SlicerPythonCLIExample

Sorry for the late response. Do I need to runSync CLI modules in separated file ? The BlurImage CLI seems still frozen GUI when I add time.sleep(5) into BlurImage.py

Btw, the SlicerProcesses works pretty well. However, is there any way to monitor the progress of the process run in background ?

Many thanks for yours support

RunSync blocks the main thread until the execution completes, so don’t use it of you want to process in the background.

The current SlicerProcesses code isn’t set up for progress reporting. There could be lots of ways to do it, Slicer CLI modules use a convention of embedding xml snippets in the output that triggers automatic progress updates in the GUI. Another option would be to set up a connection like OpenIGTLink to pass data. Or one could create a custom network protocol.

1 Like