Trigger event when CLI run has completed

As in the title I would like to be able to trigger some code after a CLI run has completed.

I know I can use the parameter wait_for_completion=True to pause the code execution, however if I do this the GUI does not update and the qCLIProgressBar does not run making it look as though the program has hung.

I have tried setting a connect condition to be triggered by the progress bar…

self.bar3.connect(‘valueChanged(int)’, self.onBar3)

but the qSlicerCLIProgressBar does not seem to give out the same signals as the qProgressBar.

I also tried using a While / Sleep loop to check the status of the cliNode (cliNode.GetStatus()) but this freezes the GUI just like the wait_for_completion parameter.

Is there any way to wait for the CLI to complete without freezing the GUI or (which would seem neater to me) to trigger a new routine once it has completed.

Thanks

Yes, you can put an observer on the command line module node and get events when the state changes. See “Running CLI in the background” here:

https://www.slicer.org/wiki/Documentation/Nightly/Developers/Python_scripting#Running_a_CLI_from_Python

2 Likes

Hi @pieper,
I am facing an issue when trying to react to a cli node’s execution completion. I saw the example you have linked below.

I attempted to do the same in cpp. The problem I am facing is that, until I open the python console and click enter, or open the data module, the status of my CLI node is not updating. For example, I send a request for a CLI module’s execution and opened the CLI module’s widget. The widget’s timer keeps updating till the CLI module runs. For example if the module’s execution took 20s, the widget reaches 20s and stops counting. Once the data module is opened after the 20s it needed for execution, the callbacks I registered are getting called. But these callbacks had to run when the vtkMRMLCommandLineModuleNode::StatusModifiedEvent fired as soon as the 20s where over, not when I am opening the data module or clicking enter into the python console. It seems that the event - vtkMRMLCommandLineModuleNode::StatusModifiedEvent is not getting fired even after the CLI node has finished execution.

This is how I am registering the callbacks inside my qSlicerExampleModuleWidget :-

vtkSmartPointer<vtkCallbackCommand> statusCallback = vtkSmartPointer<vtkCallbackCommand>::New();
statusCallback->SetCallback([](vtkObject* caller, unsigned long eventId, void* clientData, void* callData) {
  auto* moduleWidget = static_cast<qSlicerExampleModuleWidget*>(clientData);
  if (!moduleWidget)
  {
    qCritical() << Q_FUNC_INFO << ": failed to cast clientData to qSlicerExampleModuleWidget";
    return;
  }

  auto* cliNode = vtkMRMLCommandLineModuleNode::SafeDownCast(caller);
  if (!cliNode)
  {
    qCritical() << Q_FUNC_INFO << ": failed to cast caller to vtkMRMLCommandLineModuleNode";
    return;
  }

  moduleWidget->onCliStatusChanged(caller, (void*)cliNode->GetID(), eventId, callData);
});
statusCallback->SetClientData(this);
cliNode->AddObserver(vtkMRMLCommandLineModuleNode::StatusModifiedEvent, statusCallback);

cliNode->SetParameterAsString("inputPathA", std::string(inputPathA));
cliNode->SetParameterAsString("inputPathB", std::string(inputPathB));

cliLogic->Apply(cliNode, false);

qInfo() << Q_FUNC_INFO << ": CLI request sent successfully";

Whatever is inside moduleWidget->onCliStatusChangedis only getting called when I move to the data module or click enter in the python console. Any suggestions on why this could be happening? I tried using the vtkCommand::ModifiedEvent as well but got the same results. Any help would be greatly appreciated.

Thanks!

Hi all,
When I am running the CLI module synchronously, the callbacks are executing as soon as the CLI execution completes. But it is in the asynchronous CLI execution I am facing problems on the CLI node’s status updating reliably.

Working code :-

**everything else the same**

 cliLogic->ApplyAndWait(cliNode, false);