# Write python bindings

**URL:** <https://discourse.slicer.org/t/write-python-bindings/18066>\
**Category:** Development\
**Created:** [June 10, 2021, 4:32pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066 "2021-06-10T16:32:30Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [June 10, 2021, 4:32pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/1 "2021-06-10T16:32:30Z")

</div>

Hi,

I have some Qt derived classes (widgets) written in C++ and used in SlicerCAT and I would like to bind them in python.

I have some experience of working with [pybind11](https://github.com/pybind/pybind11) and I do use it in my libraries that are not connected to Qt.  
There is also automatic code generator [rosetta-binder](https://github.com/RosettaCommons/binder) based on pybind11.

I also know that [Qt also provides its method](https://www.qt.io/blog/2018/05/31/write-python-bindings) to convert C++ to python using [Shiboken tool](https://doc.qt.io/qtforpython/shiboken6/). Though I have not tested it yet.

So I would appreciate if someone could give an advice wich way is better and what should I use to convert C++ Qt based widget to python and use it in SlicerCAT

---

<div class="post-metadata">

**Author:** ![jamesobutler](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jamesobutler/32/7511_2.png) [@jamesobutler](https://discourse.slicer.org/u/jamesobutler)\
**Post date:** [June 10, 2021, 6:37pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/2 "2021-06-10T18:37:29Z")

</div>

Is there a reason you choose to create your Qt based widget in C++ rather than creating the widget in python? Are you using it in other C++ code?

You can create a custom QWidget from the python interface for use in other python code.

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [June 10, 2021, 9:49pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/3 "2021-06-10T21:49:01Z")

</div>

> [@jamesobutler](#):
>
> Is there a reason you choose to create your Qt based widget in C++ rather than creating the widget in python? Are you using it in other C++ code?

That is the question that I ask myself.  
I think there are two reasons:

1. I already implemented them in C++
2. I think that in the future I encounter a situation when I will need to bind C++ class to python and thus it means that I will simply postpone this task if I decide not to use bindings now.

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [June 10, 2021, 9:55pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/4 "2021-06-10T21:55:44Z")

</div>

@keri did you look at how other Qt classes are wrapped in Slicer using PythonQt? This would be more consistent, and hopefully easier, than introducing another python wrapping method. I haven’t tried it in SlicerCAT, but I believe all the same functionality is available.

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [June 10, 2021, 10:29pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/5 "2021-06-10T22:29:52Z")

</div>

Hi,

I have made an attempt but didn’t find a file (or class) where it is done. If you know an example in Slicer please say where to look for it.

Also as I know [PyQt](https://www.riverbankcomputing.com/software/pyqt/), [PySide2 (official)](https://wiki.qt.io/Qt_for_Python) and [PythonQt](https://mevislab.github.io/pythonqt/index.html) they are all different projects am I right? Which ones Slicer is using?

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [June 10, 2021, 10:37pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/6 "2021-06-10T22:37:14Z")

</div>

Slicer uses PythonQt very extensively so you can look at any QObject or QWidget subclass in Slicer and the API will be exposed to Python through PythonQt. Basically, the public interface is wrapped, so Signals, Slots, and Properties are all available. In addition methods marked with the Q\_INVOKABLE macro will also be wrapped. All [the python-related developer tutorials](https://www.slicer.org/wiki/Documentation/4.10/Training#Tutorials_for_software_developers) make use of this.

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [June 10, 2021, 10:43pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/7 "2021-06-10T22:43:38Z")

</div>

thank you! I will focus on this and try to sort it out

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [June 29, 2021, 12:25am UTC](https://discourse.slicer.org/t/write-python-bindings/18066/8 "2021-06-29T00:25:01Z")

</div>

Hi,

I can’t actually find a comprehensive example how Slicer uses PythonQt to wrap C++ classes to python.  
I’ve seen examples on PythonQt github but can’t apply it to my class.

For example I can do:

```python
import PythonQt

dir(PythonQt)

```

the output would be:

```auto
['BoolResult', 'CTKCore', 'CTKScriptingPythonWidgets', 'CTKVisualizationVTKCore', 
'CTKVisualizationVTKWidgets', 'CTKWidgets', 'Debug', 'Qt', 'QtCore', 'QtGui', 'QtNetwork', 'QtUiTools', 
' __doc__', ' __loader__', ' __name__', ' __package__', ' __spec__', 'private', 'qMRMLWidgets', 
'qSlicerAnnotationsModuleWidgets', 'qSlicerBaseQTApp', 'qSlicerBaseQTCLI', 'qSlicerBaseQTCore', 
'qSlicerBaseQTGUI', 'qSlicerMarkupsModuleWidgets', 'qSlicerMarkupsSubjectHierarchyPlugins', 
'qSlicerModelsModuleWidgets', 'qSlicerModelsSubjectHierarchyPlugins', 'qSlicerPlotsModuleWidgets', 
'qSlicerPlotsSubjectHierarchyPlugins', 'qSlicerSegmentationsEditorEffects', 
'qSlicerSegmentationsModuleWidgets', 'qSlicerSegmentationsSubjectHierarchyPlugins', 
'qSlicerSequencesModuleWidgets', 'qSlicerSubjectHierarchyModuleWidgets', 
'qSlicerTablesModuleWidgets', 'qSlicerTablesSubjectHierarchyPlugins', 
'qSlicerTerminologiesModuleWidgets', 'qSlicerTextsModuleWidgets', 
'qSlicerTextsSubjectHierarchyPlugins', 'qSlicerTransformsModuleWidgets', 
'qSlicerTransformsSubjectHierarchyPlugins', 'qSlicerUnitsModuleWidgets', 
'qSlicerVolumeRenderingModuleWidgets', 'qSlicerVolumeRenderingSubjectHierarchyPlugins', 
'qSlicerVolumesModuleWidgets', 'qSlicerVolumesSubjectHierarchyPlugins']

```

then I look to GUI elements:

```python
dir(PythonQt.qSlicerBaseQTGUI)

```

and among many output classes I can see `qSlicerDirectoryListView` for example. Assuming that this class was written in C++ and binded to python I search for `qSlicerDirectoryListView.h` and `qSlicerDirectoryListView.cxx`. I have found them in `Base/QTGUI/` folder. To my surprise these files doesn’t contain any `PythonQt` mentionning…

From my point of view to bind C++ class to python I need to add somwhere `#include <PythonQt.h>` and `PythonQt::self()->registerClass(&qMyClass::staticMetaObject);`. And to check if it works I should run my application and in python interpreter do something like:

```python
import PythonQt
dir(PythonQt)

```

and among the output I should be able to find `qMyClass`. Am I right? Though suspiciously simple 🙂

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [June 29, 2021, 1:20am UTC](https://discourse.slicer.org/t/write-python-bindings/18066/9 "2021-06-29T01:20:18Z")

</div>

Python wrapping is done fully automatically, by CMake macros (at the lowest level, it is implemented in `ctkMacroWrapPythonQt` in CTK library). As long as you build the library using Slicer macros, specify `WRAP_PYTHONQT` flag, and the Python wrapper can parse your header file, all your Qt classes will be automatically available in Python.

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [June 29, 2021, 8:12pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/10 "2021-06-29T20:12:04Z")

</div>

Thank you! I just got first positive results by using `WRAP_PYTHONQT` inside `slicerMacroBuildAppLibrary` and I’m able to use my Qt based custom widgets

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [June 30, 2021, 12:04am UTC](https://discourse.slicer.org/t/write-python-bindings/18066/11 "2021-06-30T00:04:15Z")

</div>

What maybe the reason why not all my widgets were binded to python?  
For example I have:

```auto
slicerMacroBuildAppLibrary(
  NAME ${APPLIB_NAME} # qColadaApp
  DESCRIPTION_SUMMARY ${${PROJECT_NAME}_DESCRIPTION_SUMMARY}
  DESCRIPTION_FILE ${${PROJECT_NAME}_DESCRIPTION_FILE}
  APPLICATION_NAME ${${PROJECT_NAME}_APPLICATION_NAME}
  EXPORT_DIRECTIVE "Q_COLADA_APP_EXPORT"
  FOLDER ${${PROJECT_NAME}_FOLDER}
  SRCS ${APPLIB_SRCS}
  MOC_SRCS ${APPLIB_MOC_SRCS}
  UI_SRCS ${APPLIB_UI_SRCS}
  RESOURCES ${APPLIB_RESOURCES}
  WRAP_PYTHONQT
  TARGET_LIBRARIES ${APPLIB_TARGET_LIBRARIES}
  INCLUDE_DIRECTORIES ${APPLIB_DIRS}
  )

```

CMake variable `APPLIB_SRCS` contains a list of `.cxx` and `.h` files that implement both Qt derived widgets and non Qt classes.  
`APPLIB_MOC_SRCS` contains a list of `.h` files that declare all Qt derived objects with `Q_OBJECT` macro.

Generated module is called `qColadaAppPythonQt`. Then I can check binded classes:

```python
import qColadaAppPythonQt

dir(qColadaAppPythonQt)

```

There I can see that only half of my classes were binded (half of `APPLIB_MOC_SRCS` var-list classes)

Also I tried it on both Windows and Ubuntu and seems that on Ubuntu a little more classes were binded than on Windows.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [June 30, 2021, 1:10am UTC](https://discourse.slicer.org/t/write-python-bindings/18066/12 "2021-06-30T01:10:15Z")

</div>

If a class is not wrapped then most likely it contains something that the wrapper cannot parse. You can determine what it is by commenting out everything in the .h file and gradually adding back lines and see which line is troublesome. If it is not clear why that specific line caused the wrapping to fail then you can ask us here, we may have suggestions for how to change it.

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [June 30, 2021, 2:09pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/13 "2021-06-30T14:09:50Z")

</div>

I’m afraidn that the very simple exmple doesn’t work.

In my project I have `qColadaH5TreeView` base class that is inherited by some other classes. But it is difficult to comment something directly in this class as it would lead to many code changes in project.

Thus I created `qColadaH5TreeView_TEST` class wich is the same but with postfix `_TEST`. I have cut almost everything from it. Here it is:  
**qColadaH5TreeView\_TEST.h**

```cpp
#ifndef __qColadaH5TreeView_TEST_h
#define __qColadaH5TreeView_TEST_h

// Qt includes
#include <QTreeView>

// Colada includes
#include "qColadaAppExport.h"

class qColadaH5TreeView_TESTPrivate;

class Q_COLADA_APP_EXPORT qColadaH5TreeView_TEST : public QTreeView {
  Q_OBJECT

public:
  explicit qColadaH5TreeView_TEST(QWidget *parent = nullptr);
  virtual ~qColadaH5TreeView_TEST() override;

protected:
  QScopedPointer<qColadaH5TreeView_TESTPrivate> d_ptr;

  explicit qColadaH5TreeView_TEST(qColadaH5TreeView_TESTPrivate *pimpl,
                             QWidget *parent);

private:
  Q_DECLARE_PRIVATE(qColadaH5TreeView_TEST);
  Q_DISABLE_COPY(qColadaH5TreeView_TEST);
};

#endif

```

**qColadaH5TreeView\_TEST.cxx**

```cpp
// Colada includes
#include "qColadaH5TreeView_TEST.h"
#include "qColadaH5TreeView_TEST_p.h"

qColadaH5TreeView_TESTPrivate::qColadaH5TreeView_TESTPrivate(qColadaH5TreeView_TEST &q)
    : q_ptr(&q) {}

qColadaH5TreeView_TESTPrivate::~qColadaH5TreeView_TESTPrivate() {}

void qColadaH5TreeView_TESTPrivate::init() {
  Q_Q(qColadaH5TreeView_TEST);
  // do some initialization
}

qColadaH5TreeView_TEST::qColadaH5TreeView_TEST(QWidget *parent)
    : QTreeView(parent), d_ptr(new qColadaH5TreeView_TESTPrivate(*this)) {
  Q_D(qColadaH5TreeView_TEST);
  d->init();
}

qColadaH5TreeView_TEST::qColadaH5TreeView_TEST(qColadaH5TreeView_TESTPrivate *pimpl, QWidget *parent)
    : QTreeView(parent), d_ptr(pimpl) {
  // init() is called by derived class.
}

qColadaH5TreeView_TEST::~qColadaH5TreeView_TEST() {}

```

**qColadaH5TreeView\_TEST\_p.h**

```cpp
#ifndef __qColadaH5TreeView_TEST_p_h
#define __qColadaH5TreeView_TEST_p_h

// Colada includes
#include "qColadaH5TreeView_TEST.h"

class Q_COLADA_APP_EXPORT qColadaH5TreeView_TESTPrivate
{
	Q_DECLARE_PUBLIC(qColadaH5TreeView_TEST);

protected:
	qColadaH5TreeView_TEST* const q_ptr;

public:
	typedef qColadaH5TreeView_TESTPrivate Superclass;
	qColadaH5TreeView_TESTPrivate(qColadaH5TreeView_TEST& q);
	virtual ~qColadaH5TreeView_TESTPrivate();

	virtual void init();
};

#endif

```

For this class I still can’t get bindings. These files are included to my project but I don’t use this `qColadaH5TreeView_TEST` anywhere (I don’t know should I use it to make bindings?) but `qColadaH5TreeView` is in use of course.

The build output is:

```auto
Build started...
1>------ Build started: Project: SlicerConfigureVersionHeader, Configuration: Debug x64 ------
2>------ Build started: Project: vtkITKHierarchy, Configuration: Debug x64 ------
3>------ Build started: Project: vtkAddonHierarchy, Configuration: Debug x64 ------
4>------ Build started: Project: vtkSegmentationCoreHierarchy, Configuration: Debug x64 ------
1>Configuring vtkSlicerVersionConfigure.h
4>For vtkSegmentationCore - updating vtkSegmentationCoreHierarchy.txt
1>-- Configuring Colada release type [Experimental]
1>-- Found Git: C:/Program Files/Git/cmd/git.exe
1>-- Configuring Slicer version [4.13.0-2021-05-10]
1>-- Configuring Slicer revision [29890]
1>-- Configuring Colada version [0.1.0-2021-03-30]
1>-- Configuring Colada revision [2]
5>------ Build started: Project: vtkTeemHierarchy, Configuration: Debug x64 ------
6>------ Build started: Project: MRMLCoreHierarchy, Configuration: Debug x64 ------
7>------ Build started: Project: MRMLLogicHierarchy, Configuration: Debug x64 ------
8>------ Build started: Project: MRMLCLIHierarchy, Configuration: Debug x64 ------
9>------ Build started: Project: SlicerBaseLogicHierarchy, Configuration: Debug x64 ------
10>------ Build started: Project: qColadaApp, Configuration: Debug x64 ------
10>Generating moc_qColadaH5TreeView_TEST.cpp
10>qColadaH5TreeView_TEST.cxx
10>moc_qColadaH5TreeView_TEST.cpp
10>Generating Code...
10>qColadaApp.vcxproj -> C:\C\d\Slicer-build\bin\Debug\qColadaApp.dll
========== Build: 10 succeeded, 0 failed, 18 up-to-date, 0 skipped ==========

```

By the way more complex classes that uses third party libraries inside the logic and are inherited from `QDialog` or `QTableView` are binded without problems.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 2, 2021, 6:23pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/14 "2021-07-02T18:23:42Z")

</div>

Thank you, this will be useful. Could you attach your CMakeLists.txt file as well?

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [July 2, 2021, 11:29pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/15 "2021-07-02T23:29:11Z")

</div>

sure, here is the `CMakeLists.txt` where I use Slicer’s macro to build libs:

```auto
#============================================================================
#
# Copyright (c) Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0.txt
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#============================================================================

project(ColadaApp)

include(SlicerMacroBuildApplication)

# --------------------------------------------------------------------------
# Properties
# --------------------------------------------------------------------------
SlicerReadApplicationProperties()

# --------------------------------------------------------------------------
# Folder
# --------------------------------------------------------------------------
set(${PROJECT_NAME}_FOLDER "App-${PROJECT_NAME}")

find_package(OpenMP REQUIRED) # Colada needs OpenMP
find_package(ZLIB REQUIRED)
find_package(HDF5 REQUIRED CONFIG) # based on HDF5_DIR
find_package(h5geo REQUIRED CONFIG) # based on h5geo_DIR
find_package(GDAL REQUIRED)

# GDAL::GDAL depends on many libs (TIFF, GEOS etc). Here we are linking them
if(DEFINED GDAL_LIBS)
  target_link_libraries(GDAL::GDAL INTERFACE ${GDAL_LIBS})
endif()

# --------------------------------------------------------------------------
# Application library
# --------------------------------------------------------------------------
set(APPLIB_NAME "q${PROJECT_NAME}")

set(APPLIB_SRCS
  qColadaH5TreeView_TEST.cxx
  qColadaH5TreeView_TEST.h

  qColadaAppMainWindow.cxx
  qColadaAppMainWindow.h

  ColadaDBCore.cxx
  ColadaDBCore.h
  ColadaUtil.cxx
  ColadaUtil.h
  
  qAppStyle.cxx
  qAppStyle.h
  qColadaNewProject.cxx
  qColadaNewProject.h
  qCRSDropTableView.h
  qCRSDropTableView.cxx
  qCRSWidget.cxx
  qCRSWidget.h
  qREValidator.cxx
  qREValidator.h
  qColadaH5TreeView.cxx
  qColadaH5TreeView.h
  qColadaH5SeisTreeView.cxx
  qColadaH5SeisTreeView.h
  qColadaH5SurfTreeView.cxx
  qColadaH5SurfTreeView.h
  qColadaH5WellTreeView.cxx
  qColadaH5WellTreeView.h
  qColadaH5Item.cxx
  qColadaH5Item.h
  qColadaH5ItemDelegate.cxx
  qColadaH5ItemDelegate.h
  qColadaH5Model.cxx
  qColadaH5Model.h
  qColadaH5SeisModel.cxx
  qColadaH5SeisModel.h
  qColadaH5SurfModel.cxx
  qColadaH5SurfModel.h
  qColadaH5WellModel.cxx
  qColadaH5WellModel.h
  qColadaH5ProxyModel.cxx
  qColadaH5ProxyModel.h
  qColadaReader.h
  qColadaReader.cxx
  qCopyPasteTableView.h
  qCopyPasteTableView.cxx
  qScienceSpinBox.h
  qScienceSpinBox.cxx
  qColadaSegyReader.h
  qColadaSegyReader.cxx
  qComboBoxDelegate.h
  qComboBoxDelegate.cxx
  qSpinBoxDelegate.h
  qSpinBoxDelegate.cxx
  qScienceSpinBoxDelegate.h
  qScienceSpinBoxDelegate.cxx
  qLineEditDelegate.h
  qLineEditDelegate.cxx
  qPathEditDelegate.h
  qPathEditDelegate.cxx
  SegyRead.h
  SegyRead.cxx
  )

set(APPLIB_MOC_SRCS
  qColadaH5TreeView_TEST.h

  qColadaAppMainWindow.h
  qAppStyle.h
  qColadaNewProject.h
  qCRSDropTableView.h
  qCRSWidget.h
  qREValidator.h
  qColadaH5TreeView.h
  qColadaH5SurfTreeView.h
  qColadaH5SeisTreeView.h
  qColadaH5WellTreeView.h
  qColadaH5ItemDelegate.h
  qColadaH5Model.h
  qColadaH5SurfModel.h
  qColadaH5SeisModel.h
  qColadaH5WellModel.h
  qColadaH5ProxyModel.h
  qColadaReader.h
  qCopyPasteTableView.h
  qScienceSpinBox.h
  qColadaSegyReader.h
  qComboBoxDelegate.h
  qSpinBoxDelegate.h
  qScienceSpinBoxDelegate.h
  qLineEditDelegate.h
  qPathEditDelegate.h
  )

set(APPLIB_UI_SRCS
  )

set(APPLIB_RESOURCES
  Resources/App.qrc
  )

set(APPLIB_TARGET_LIBRARIES 
  # ColadaCore # this may be useful when splitting qColadaApp by few subprojects
  OpenMP::OpenMP_CXX
  hdf5::hdf5-shared
  h5geo
  GDAL::GDAL
  ${julia_LIBS}
  )

# Sanity checks
set(include_dirs
  ${Eigen3_INCLUDE_DIR}
  ${h5gt_INCLUDE_DIR}
  ${magic_enum_INCLUDE_DIR}
  ${julia_INCLUDE_DIR}
  )

foreach(var ${include_dirs})
  if(NOT EXISTS "${var}")
    message(FATAL_ERROR "Path to include dir: ${var} doesn't exist!")
  endif()
endforeach()

set(APPLIB_DIRS 
  ${Eigen3_INCLUDE_DIR}
  ${h5gt_INCLUDE_DIR}
  ${magic_enum_INCLUDE_DIR}
  ${julia_INCLUDE_DIR}
  )

slicerMacroBuildAppLibrary(
  NAME ${APPLIB_NAME}
  DESCRIPTION_SUMMARY ${${PROJECT_NAME}_DESCRIPTION_SUMMARY}
  DESCRIPTION_FILE ${${PROJECT_NAME}_DESCRIPTION_FILE}
  APPLICATION_NAME ${${PROJECT_NAME}_APPLICATION_NAME}
  EXPORT_DIRECTIVE "Q_COLADA_APP_EXPORT"
  FOLDER ${${PROJECT_NAME}_FOLDER}
  SRCS ${APPLIB_SRCS}
  MOC_SRCS ${APPLIB_MOC_SRCS}
  UI_SRCS ${APPLIB_UI_SRCS}
  RESOURCES ${APPLIB_RESOURCES}
  WRAP_PYTHONQT
  TARGET_LIBRARIES ${APPLIB_TARGET_LIBRARIES}
  INCLUDE_DIRECTORIES ${APPLIB_DIRS}
  )

# --------------------------------------------------------------------------
# Application executable
# --------------------------------------------------------------------------

# Configure launcher only for the main application
set(extra_args)
if(${PROJECT_NAME} STREQUAL ${Slicer_MAIN_PROJECT})
  set(extra_args CONFIGURE_LAUNCHER)
endif()

set(APP_SRCS
  Main.cxx
  )

set(APP_TARGET_LIBRARIES ${APPLIB_NAME})

slicerMacroBuildApplication(
  NAME ${PROJECT_NAME}
  APPLICATION_NAME ${${PROJECT_NAME}_APPLICATION_NAME}
  LAUNCHER_SPLASHSCREEN_FILE ${${PROJECT_NAME}_LAUNCHER_SPLASHSCREEN_FILE}
  APPLE_ICON_FILE ${${PROJECT_NAME}_APPLE_ICON_FILE}
  WIN_ICON_FILE ${${PROJECT_NAME}_WIN_ICON_FILE}
  LICENSE_FILE ${${PROJECT_NAME}_LICENSE_FILE}
  FOLDER ${${PROJECT_NAME}_FOLDER}
  SRCS ${APP_SRCS}
  TARGET_LIBRARIES ${APP_TARGET_LIBRARIES}
  TARGET_NAME_VAR "APP_TARGET_NAME"
  DEFAULT_SETTINGS_FILE Resources/Settings/DefaultSettings.ini
  ${extra_args}
  )

#-----------------------------------------------------------------------------
message("Slicer_INSTALL_ROOT: ${Slicer_INSTALL_ROOT}")
message("Slicer_INSTALL_BIN_DIR: ${Slicer_INSTALL_BIN_DIR}")
message("julia_ROOT: ${julia_ROOT}")
# Install extension deps packages
# install(CODE "message(\"CPack: - Install directory: ${julia_ROOT}\")")
install(
  DIRECTORY ${julia_ROOT}/ # '/' in the end is necessary
  DESTINATION ${Slicer_INSTALL_ROOT}/julia
  COMPONENT RuntimeLibraries # 'ALL' doesn't work
  )

# Install libraries
include(${Slicer_SOURCE_DIR}/CMake/SlicerFunctionInstallLibrary.cmake)
slicerInstallLibrary(
  FILE ${HDF5_ROOT}/lib/hdf5
  DESTINATION ${Slicer_INSTALL_BIN_DIR}
  COMPONENT RuntimeLibraries
  )
slicerInstallLibrary(
  FILE ${h5geo_ROOT}/lib/h5geo
  DESTINATION ${Slicer_INSTALL_BIN_DIR}
  COMPONENT RuntimeLibraries
  )

set(EXTENSION_NAME Colada)
set(CPACK_INSTALL_CMAKE_PROJECTS "${CPACK_INSTALL_CMAKE_PROJECTS};${HDF5_ROOT};HDF5;ALL;/")
set(CPACK_INSTALL_CMAKE_PROJECTS "${CPACK_INSTALL_CMAKE_PROJECTS};${h5geo_ROOT};h5geo;ALL;/")
set(CPACK_INSTALL_CMAKE_PROJECTS "${CPACK_INSTALL_CMAKE_PROJECTS};${julia_ROOT};julia;ALL;/")

#-----------------------------------------------------------------------------
# list(APPEND CPACK_INSTALL_CMAKE_PROJECTS "${CMAKE_BINARY_DIR};${EXTENSION_NAME};ALL;/")
# list(APPEND CPACK_INSTALL_CMAKE_PROJECTS "${${EXTENSION_NAME}_CPACK_INSTALL_CMAKE_PROJECTS}")
# include(${Slicer_EXTENSION_GENERATE_CONFIG})
# include(${Slicer_SOURCE_DIR}/CMake/SlicerCPack.cmake)
include(${Slicer_SOURCE_DIR}/CMake/SlicerExtensionGenerateConfig.cmake)
include(${Slicer_SOURCE_DIR}/CMake/SlicerExtensionCPack.cmake)

message("HDF5_ROOT: ${HDF5_ROOT}")
message("CPACK_INSTALL_CMAKE_PROJECTS: ${CPACK_INSTALL_CMAKE_PROJECTS}")

```

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [July 13, 2021, 11:26pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/16 "2021-07-13T23:26:44Z")

</div>

I’m sorry, that was my carelessness…  
I simply had to rebuild project `qColadaAppPythonQt` in visual studio (previously I only used to rebuild `qColadaApp` project)

Now I can see that all my widgets are binded in python

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 14, 2021, 1:29am UTC](https://discourse.slicer.org/t/write-python-bindings/18066/17 "2021-07-14T01:29:22Z")

</div>

It’s great that you’ve figured it out. I reviewed the code and did not find anything wrong and wanted to build these files - but now I don’t need to!

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [July 17, 2021, 10:10am UTC](https://discourse.slicer.org/t/write-python-bindings/18066/18 "2021-07-17T10:10:40Z")

</div>

Is it possible to bind C++ functions in namespace using PythonQt?

For example I have:

```cpp
namespace dbcore {
///
/// \brief createDB creates new database as a DEFAULT connection
/// \param fullName
/// \return NOT opened DB
///
QSqlDatabase Q_COLADA_APP_EXPORT createDB(const QString &prjPath, QString &prjName){
  if (QFileInfo(prjName).suffix().compare("db", Qt::CaseInsensitive) != 0) {
    prjName += ".db";
  }
  QDir dir(prjPath + "/" + prjName);
  QString DBFullName = dir.absolutePath();
  QSqlDatabase DB =
      QSqlDatabase::addDatabase("QSQLITE"); // it will be default connection
  DB.setDatabaseName(DBFullName);
  return DB;
}

} // dbcore

```

and I’m thinking to make python bindings for `dbcore::createDB(const QString &prjPath, QString &prjName)` function.  
Using `WRAP_PYTHONQT` flag inside cmake script doesn’t work of course.  
I guess it should be done in similar way as it is done in [PythonQt tests](https://github.com/MeVisLab/pythonqt/blob/8137f1fff3d3996d8fb6a49c0f502852c29b929f/tests/PythonQtTests.cpp#L74) but here I bind function and not a class…

Maybe somebody has experience of doing that?

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 17, 2021, 10:49pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/19 "2021-07-17T22:49:02Z")

</div>

If you use PythonQt for Python wrapping then you can use decorators to make static or global functions available. See fore example here:

> <https://github.com/commontk/CTK/blob/693c99ab5e76ebc664194219d1583508df758879/Libs/Core/ctkCorePythonQtDecorators.h#L239-L253>

---

<div class="post-metadata">

**Author:** ![keri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/keri/32/11618_2.png) [@keri](https://discourse.slicer.org/u/keri)\
**Post date:** [July 19, 2021, 11:35pm UTC](https://discourse.slicer.org/t/write-python-bindings/18066/20 "2021-07-19T23:35:11Z")

</div>

One more question about PythonQt wrapper:

I’m trying to wrap C++ class that has a method that accept third party-library’s type argument and that third party library is C++ library that also has python bindings using **pybind11**. So PythonQt doesn’t know how that third party class looks in python and thus I cannot pass object of that class as an argument in python.

**For examle:**  
I have a simple class:

```cpp
#ifndef __qColadaTreeTEST_h
#define __qColadaTreeTEST_h

// Qt includes
#include <QTreeView>

// Colada includes
#include "qColadaAppExport.h"

// h5gt includes
#include <h5gt/H5File.hpp> // has python bindings using pybind11 

class Q_COLADA_APP_EXPORT qColadaTreeTEST : public QTreeView {
  Q_OBJECT

public:
  explicit qColadaTreeTEST(QWidget *parent = nullptr);
  ~qColadaTreeTEST() = default;

public slots:
  bool addH5File(h5gt::File file); // file - is of type `h5gt::File` -> it has python bindings
};

#endif

```

Here `bool addH5File(h5gt::File file)` accepts `h5gt::File`-type argument. `h5gt` is a C++ library and I wrote python bindings for it using `pybind11`. `h5gt` library is available in my SlicerCAT.

After PythonQt has successfully created bindings for `qColadaTreeTEST` I do in SlicerCAT’s python:

```python
import qColadaAppPythonQt
q = qColadaAppPythonQt.qColadaTreeTEST()

from h5gtpy import h5gt
file_name = 'D:/tmp/test.h5'
file = h5gt.File(file_name, h5gt.OpenFlag(h5gt.ReadWrite | h5gt.Create | h5gt.Truncate))

q.addH5File(file) // here I get the following error:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
ValueError: Called addH5File(h5gt::File file) -> bool with wrong arguments: (<h5gtpy._h5gt.File object at 0x0000022035169730>,)

```

thus python (and PythonQt) can’t match C++ class `h5gt::File` with python `h5gtpy._h5gt.File` python type. How to inform PythonQt that `h5gt::File` C++ class is the same as `h5gtpy._h5gt.File` in python?

P.S.  
I did exactly the same using pybind when I was writing python wrapper for my `h5geo` C++ library that depends on `h5gt` and I solved this by preliminary importing `h5gt` module inside wrapping code:

```cpp
PYBIND11_MODULE(_h5geo, m) {
  py::module_::import("h5gtpy._h5gt"); // this code informs pybind about h5gt types

...
}

```

Probably I should act in similar way? Can’t understand where should I import `h5gt` module as it needs to be compiled (it must be already known) before `qColadaTreeTEST` class is compiled.

Now the wrapper for `qColadaTreeTEST` is done automatically using `WRAP_PYTHONQT` key word inside Slicer’s macro in CMakeLists.txt

[Next page](https://discourse.slicer.org/t/write-python-bindings/18066.md?page=2)
