Calling Python from C++

Hi, as the title suggests, the question is whether there is a possibility to call a scripted python module from C++, and if yes, how to do that.

In general, infrastructure is implemented in C++ (it is a bit more work but code is usually more robust, easier to maintain, and has better performance), which is easily accessible from both Python and C++.

If you want to call Python from C++ then it means that infrastructure-like code is implemented in Python, which is not desirable.

If you are sure that you must call Python from C++ then you can use a Python scripted CLI module with a C++ interface (the same way as you would run any other CLI module from C++) or you can run arbitrary Python code using evalScript.

Yes, that’s clear. The question was regarding a Python scripted CLI (e.g. Surface Toolkit) that I want to use in my workflow. I tried it with pattern I used for calling CLI modules, but somehow I got null pointers… I will try again…

Currently, surface toolkit is a Python scripted module, not a CLI. We left it like this, because it exposes very simple features (few lines of code each). The module is currently being reworked. What Surface toolbox feature would you like to use in your module?

Sure, wrong terminology on my side.
I find the ‘Connectivity’ tool very handy. I saw in the source code that there was a suggestion to consider a certain minimum size for the individual parts, which I also would find very useful.

Sorry, I’m stuck with this one. Is there a difference between a Python scripted CLI module and a Python scripted module?

For calling the SurfaceToolbox this is what I have:

qSlicerScriptedLoadableModule* scrModule = static_cast<qSlicerScriptedLoadableModule*>(qSlicerCoreApplication::application()->moduleManager()->module("SurfaceToolbox"));
qSlicerScriptedLoadableModuleWidget *scrWidget = static_cast<qSlicerScriptedLoadableModuleWidget*>(scrModule->widgetRepresentation());
vtkSlicerScriptedLoadableModuleLogic* moduleLogic = vtkSlicerScriptedLoadableModuleLogic::SafeDownCast(scrModule->logic());

// create scripted module node
d->scrNode = vtkMRMLScriptedModuleNode::SafeDownCast(scene->CreateNodeByClass("vtkMRMLScriptedModuleNode"));
d->scrNode->Register(d);

// Add node to the scene
scene->AddNode(d->scrNode);

// set node to widget
scrWidget->setEditedNode(d->scrNode);

// set parameters
d->scrNode->SetParameter("connectivity", "true");

I do not know how to execute the logic, as there is no Apply method. Moreover, I don’t know how to specify the input and output models.

Considering the comments from here, I reduced the code as follows, but still the question remains: can I execute the scripted module based on the following code? How would I do that?

// get module and its widget
qSlicerScriptedLoadableModule* scrModule = static_cast<qSlicerScriptedLoadableModule*>(qSlicerCoreApplication::application()->moduleManager()->module("SurfaceToolbox"));
vtkSlicerScriptedLoadableModuleLogic* moduleLogic = vtkSlicerScriptedLoadableModuleLogic::SafeDownCast(scrModule->logic());

// create scripted module node
vtkMRMLScriptedModuleNode* scrNode = vtkMRMLScriptedModuleNode::SafeDownCast(scene->CreateNodeByClass("vtkMRMLScriptedModuleNode"));
scene->AddNode(scrNode);

// set parameters
scrNode->SetParameter("connectivity", "true");

// TBD: set input/output nodes
// TBD: start execution

You can use Python scripted modules using evalScript. For example:

PythonQt::init();
PythonQtObjectPtr context = PythonQt::self()->getMainModule();
context.evalScript(QString("import SampleData; SampleData.SampleDataLogic().downloadMRHead()"));

Hi, I am trying to call a Python script (python3.7) that runs scipy functions in Slicer C++ module. Can I do this?

There are several options for calling Python from C++ (one of them is shown in my comment above, using evalScript) and it is done at many places in Slicer. However, C++ modules provide low-level infrastructure, so it would not make sense for a C++ module to depend on Python.

If you want to implement some performance-critical processing in C++ but other features are in Python then I would recommend to:

  • create a hidden C++ loadable module that just implements performance-critical processing in its logic classes: these classes are all Python-wrapped and so can be used from either C++ of Python modules
  • create Python-scripted module that uses your C++ module’s logic and any Python packages (scipy, etc.)

Also note that VTK, ITK, and other libraries bundled with Slicer already provide many features of scipy, so you may remove the need to call Python from C++ by using those libraries instead.

1 Like