Difference between revisions of "Documentation/Nightly/Developers/Tutorials/MigrationGuide/SlicerExtension"
Tag: 2017 source edit |
|||
(42 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
<noinclude>__TOC__</noinclude> | <noinclude>__TOC__</noinclude> | ||
==Slicer Extension updates== | ==Slicer Extension updates== | ||
+ | |||
+ | ===Slicer 5.0: Supporting both VTK 8.0 and VTK 9.0 === | ||
+ | |||
+ | ==== Transition from VTK 8.0 to VTK 9.0 ==== | ||
+ | |||
+ | See [[Documentation/Nightly/Developers/Tutorials/MigrationGuide#Transition_from_VTK_8.0_to_VTK_9.0]] | ||
+ | |||
+ | ====Remove building of vtk*PythonD library==== | ||
+ | |||
+ | With VTK >= 8.90, the <code>vtk*Python</code> and <code>vtk*Python</code> libraries were merged together. | ||
+ | |||
+ | <b>To fix error messages similar to:</b> | ||
+ | |||
+ | <pre> | ||
+ | CMake Error at MarginCalculatorCommon/CMakeLists.txt:70 (set_target_properties): | ||
+ | set_target_properties Can not find target to add properties to: | ||
+ | vtkMarginCalculatorCommonPythonD | ||
+ | </pre> | ||
+ | |||
+ | The code associated with the PythonD target could be removed to support VTK >= 8.90, or it could be conditionally excluded to support older version of VTK. | ||
+ | |||
+ | '''References''' | ||
+ | |||
+ | * [https://github.com/Slicer/Slicer/commit/c658b7b428a37d6f4e925664099ee30fd4ca408c Slicer c658b7b42] ENH: Add support for building against VTK 8.2.0 or 9.0.0 | ||
+ | |||
+ | ===Slicer 5.0: ITKv4 to ITKv5=== | ||
+ | |||
+ | To remove support for ITKv4 and only support ITKv5. See [[Documentation/Nightly/Developers/Tutorials/MigrationGuide#Transition_from_ITK4_to_ITK5]], it includes | ||
+ | the following sections: | ||
+ | * [[Documentation/Nightly/Developers/Tutorials/MigrationGuide#Upgrading_to_ITKv5_or_keep_using_ITKv4_GenerateThreadedData|Upgrading to ITKv5 or keep using ITKv4 GenerateThreadedData]] | ||
+ | * [[Documentation/Nightly/Developers/Tutorials/MigrationGuide#itkMultiThreader_refactor|itkMultiThreader refactor]] | ||
+ | * [[Documentation/Nightly/Developers/Tutorials/MigrationGuide#SimpleFastMutexLock.2C_FastMutexLock_and_MutexLock_are_deprecated|SimpleFastMutexLock, FastMutexLock and MutexLock are deprecated]] | ||
+ | |||
+ | If completely removing support for ITKv4 and only supporting ITKv5 is not possible. It is possible to conditionally include the ITKv4 code. | ||
+ | |||
+ | For example: | ||
+ | |||
+ | <pre> | ||
+ | #if ITK_VERSION_MAJOR >= 5 | ||
+ | itk::ITK_THREAD_RETURN_TYPE | ||
+ | #else | ||
+ | ITK_THREAD_RETURN_TYPE | ||
+ | #endif | ||
+ | </pre> | ||
+ | |||
+ | Example of commits: | ||
+ | * ResampleDTIlogEuclidean | ||
+ | ** [https://github.com/NIRALUser/ResampleDTIlogEuclidean/commit/f779bf775aad3c4e1493ed8fa722b32623ac9561 ResampleDTIlogEuclidean@f779bf7] COMP: Use std::mutex instead of deprecated ITK implementation | ||
+ | ** [https://github.com/NIRALUser/ResampleDTIlogEuclidean/commit/ed5093b15d0ded34db08978c6c5933c36e40b803 ResampleDTIlogEuclidean@ed5093b] BUG: ITKv5: Fix tests updating ITK filters to use ITKv5 dynamic multi-threading | ||
+ | * PETTumorSegmentation | ||
+ | ** [https://github.com/QIICR/PETTumorSegmentation/pull/18/commits/4aead376ed1d909310d43496dd349e8f3b8c8210 PETTumorSegmentation PR#18] BUG: Add support for ITKv5 dynamic multithreader | ||
+ | ** [https://github.com/QIICR/PETTumorSegmentation/pull/18/commits/814a689501ab06d70d3ee3d561c14674e724a0d2 PETTumorSegmentation PR#18] COMP: Support ITKv5 refactored threading models | ||
+ | |||
+ | ===Slicer 5.0: Python2 to Python3=== | ||
+ | |||
+ | Depending on the complexity of the extension, two approaches shall be considered: | ||
+ | * code base common to Slicer 4.10 and Slicer 5.0. This means backward compatibility with the latest release is maintained. | ||
+ | * specific branch for each Slicer version (e.g <tt>master-4.10</tt> and <tt>master</tt>) | ||
+ | |||
+ | |||
+ | '''Example of commits''' | ||
+ | |||
+ | * [https://github.com/Slicer/Slicer/commit/d366e32491d13461c9c6316b3e4ed80fb4279d3f Slicer r28079] STYLE: Update python classes to follow new-style | ||
+ | * [https://github.com/fedorov/MultiVolumeImporter/commit/f9917b237c3bc3255e3c7677dc9af351dc2325e1 MultiVolumeImporter@f9917b2] STYLE: Apply lib2to3.fixes.fix_idioms to support python3 | ||
+ | * [https://github.com/fedorov/MultiVolumeImporter/commit/3edd1bc593f178f11aa92d9baa62685bc96ac540 MultiVolumeImporter@3edd1bc] ENH: Support for Python3 | ||
+ | * [https://github.com/slicersalt/ShapeVariationAnalyzer/commit/42343774c44dc78b8560fc0a9e33e3a6018cb6e1 ShapeVariationAnalyzer@4234377] STYLE: Update python scripts for python 3.x | ||
+ | * [https://github.com/QIICR/PETTumorSegmentation/pull/18/commits/b298ab8e672e1ab52ae6b189a34d9930ccac19ba PETTumorSegmentation PR#18] BUG: Add support for Python 3 | ||
+ | |||
+ | |||
+ | '''Step 1''' | ||
+ | |||
+ | Understanding the scope of changes needed to support Python 3 can be done by: | ||
+ | |||
+ | <ol start="1" style="list-style-type: decimal;"> | ||
+ | <li>installing future package (see https://python-future.org/) | ||
+ | <pre> | ||
+ | Slicer_DIR=/path/to/Slicer-SuperBuild/Slicer-build | ||
+ | ${Slicer_DIR}/../python-install/bin/PythonSlicer -m pip install future | ||
+ | </pre> | ||
+ | </li> | ||
+ | <li>applying all fixes | ||
+ | <pre> | ||
+ | for f in `find ./ -name "*.py"`; do \ | ||
+ | ${Slicer_DIR}/../python-install/bin/PythonSlicer \ | ||
+ | --launch futurize --nobackups --write $f; \ | ||
+ | done | ||
+ | </pre> | ||
+ | |||
+ | <small>{{note}} Alternatively the <tt>future</tt> package could be installed in a regular python environment and used from there. | ||
+ | |||
+ | <pre> | ||
+ | for f in `find ./ -name "*.py"`; do \ | ||
+ | futurize --nobackups --write $f; \ | ||
+ | done | ||
+ | </pre> | ||
+ | </small> | ||
+ | |||
+ | </li> | ||
+ | </ol> | ||
+ | |||
+ | This first step will apply the following transformations: | ||
+ | <pre> | ||
+ | lib2to3.fixes.fix_apply | ||
+ | lib2to3.fixes.fix_dict | ||
+ | lib2to3.fixes.fix_except | ||
+ | lib2to3.fixes.fix_exec | ||
+ | lib2to3.fixes.fix_exitfunc | ||
+ | lib2to3.fixes.fix_filter | ||
+ | lib2to3.fixes.fix_funcattrs | ||
+ | lib2to3.fixes.fix_getcwdu | ||
+ | lib2to3.fixes.fix_has_key | ||
+ | lib2to3.fixes.fix_input | ||
+ | lib2to3.fixes.fix_intern | ||
+ | lib2to3.fixes.fix_isinstance | ||
+ | lib2to3.fixes.fix_itertools | ||
+ | lib2to3.fixes.fix_itertools_imports | ||
+ | lib2to3.fixes.fix_long | ||
+ | lib2to3.fixes.fix_map | ||
+ | lib2to3.fixes.fix_methodattrs | ||
+ | lib2to3.fixes.fix_ne | ||
+ | lib2to3.fixes.fix_next | ||
+ | lib2to3.fixes.fix_nonzero | ||
+ | lib2to3.fixes.fix_numliterals | ||
+ | lib2to3.fixes.fix_operator | ||
+ | lib2to3.fixes.fix_paren | ||
+ | lib2to3.fixes.fix_raw_input | ||
+ | lib2to3.fixes.fix_reduce | ||
+ | lib2to3.fixes.fix_renamesSlicer migration guide describes how to update the code. See https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/MigrationGuide/SlicerExtension#Slicer_5.0:_Python2_to_Python3 | ||
+ | lib2to3.fixes.fix_repr | ||
+ | lib2to3.fixes.fix_standarderror | ||
+ | lib2to3.fixes.fix_sys_exc | ||
+ | lib2to3.fixes.fix_throw | ||
+ | lib2to3.fixes.fix_tuple_params | ||
+ | lib2to3.fixes.fix_types | ||
+ | lib2to3.fixes.fix_xreadlines | ||
+ | lib2to3.fixes.fix_zip | ||
+ | libfuturize.fixes.fix_absolute_import | ||
+ | libfuturize.fixes.fix_basestring | ||
+ | libfuturize.fixes.fix_cmp | ||
+ | libfuturize.fixes.fix_division_safe | ||
+ | libfuturize.fixes.fix_execfile | ||
+ | libfuturize.fixes.fix_future_builtins | ||
+ | libfuturize.fixes.fix_future_standard_library | ||
+ | libfuturize.fixes.fix_future_standard_library_urllib | ||
+ | libfuturize.fixes.fix_metaclass | ||
+ | libfuturize.fixes.fix_next_call | ||
+ | libfuturize.fixes.fix_object | ||
+ | libfuturize.fixes.fix_print_with_import | ||
+ | libfuturize.fixes.fix_raise | ||
+ | libfuturize.fixes.fix_unicode_keep_u | ||
+ | libfuturize.fixes.fix_xrange_with_import | ||
+ | libpasteurize.fixes.fix_newstyle | ||
+ | </pre> | ||
+ | |||
+ | expect these two: | ||
+ | |||
+ | <pre> | ||
+ | lib2to3.fixes.fix_idioms | ||
+ | lib2to3.fixes.fix_ws_comma | ||
+ | </pre> | ||
+ | |||
+ | <small>{{note}} If the number of changes is large, you should consider applying each fixes independently.</small> | ||
+ | |||
+ | |||
+ | '''Step 2''' | ||
+ | |||
+ | Not all changes applied automatically should be integrated. Most of the changes introducing imports from the <tt>future</tt> python package can simply be removed or removed after making use of <tt>try/except</tt> or check of <tt>sys.version_info[0]</tt>. | ||
+ | |||
+ | * Systematic conversion of keys, values or items from dictionaries do not need to be systematically converted from <tt>dict_keys</tt>/<tt>dict_values</tt>/<tt>dict_items</tt> to <tt>list</tt>. For example, this Slicer [https://github.com/Slicer/Slicer/commit/6a60207b220d35a032911faebfc03a862f37b1a2 r28077] reverted some of the automatic changes applied by the future CLI. | ||
+ | |||
+ | * Unless python classes implement the object functions <tt>next</tt> and <tt>__unicode__</tt> specific to Python 2, nothing specific should be done and <tt><b>from builtins import object</b></tt> can be removed. Automatic removal of imports can also be automated doing: | ||
+ | |||
+ | for f in `find ./ -name "*.py"`; do \ | ||
+ | sed -i '/from builtins import object/ d' $f; \ | ||
+ | done | ||
+ | |||
+ | * Unless there are performances issue associated with using <tt>range</tt> in Python 2, the <tt><b>from builtins import range</b></tt> can be removed: | ||
+ | |||
+ | for f in `find ./ -name "*.py"`; do \ | ||
+ | sed -i '/from builtins import range/ d' $f; \ | ||
+ | done | ||
+ | |||
+ | * If there are performance issue with using <tt>range</tt> in Python 2, the following could also be done: | ||
+ | |||
+ | import sys | ||
+ | if sys.version_info[0] == 2: | ||
+ | range = xrange | ||
+ | |||
+ | * Use of aliases can also be avoided by removing | ||
+ | |||
+ | from future import standard_library | ||
+ | standard_library.install_aliases() | ||
+ | |||
+ | and instead doing something like this: | ||
+ | |||
+ | try: | ||
+ | import queue | ||
+ | except ImportError: | ||
+ | import Queue as queue | ||
+ | |||
+ | For a complete list aliases, see https://python-future.org/reference.html#module-future.standard_library | ||
+ | |||
+ | * Use of <tt>old_div()</tt> function can generally be avoided by using <tt>int()</tt> | ||
+ | |||
+ | '''Step 3''' | ||
+ | |||
+ | The <tt>lib2to3.fixes.fix_idioms</tt> transformation should explicitly be applied: | ||
+ | |||
+ | <pre> | ||
+ | for f in `find ./ -name "*.py"`; do \ | ||
+ | ${Slicer_DIR}/../python-install/bin/PythonSlicer \ | ||
+ | --launch futurize -f lib2to3.fixes.fix_idioms --nobackups --write $f; \ | ||
+ | done | ||
+ | </pre> | ||
+ | |||
+ | ===Slicer 5.0: Python2 to Python3 (EditorEffect imports)=== | ||
+ | |||
+ | '''Error:''' | ||
+ | |||
+ | <pre> | ||
+ | from EditorLib import EditorLib | ||
+ | ImportError: cannot import name 'EditorLib' | ||
+ | </pre> | ||
+ | |||
+ | Import of Editor classes should be updated. For example, see [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Utilities/Templates/Modules/ScriptedEditorEffect/TemplateKeyEffect.py?r1=28122&r2=28121&pathrev=28122 r28122]. | ||
+ | |||
+ | |||
+ | '''Before:''' | ||
+ | |||
+ | <pre> | ||
+ | import EditorLib | ||
+ | from EditorLib.EditOptions import HelpButton | ||
+ | from EditorLib.EditOptions import EditOptions | ||
+ | from EditorLib import EditUtil | ||
+ | </pre> | ||
+ | |||
+ | <pre> | ||
+ | class TemplateKeyEffectOptions(EditorLib.LabelEffectOptions): | ||
+ | [...] | ||
+ | </pre> | ||
+ | |||
+ | |||
+ | '''After:''' | ||
+ | |||
+ | <pre> | ||
+ | import EditorLib | ||
+ | from EditorLib import EditOptions, HelpButton | ||
+ | from EditorLib import EditUtil | ||
+ | from EditorLib import LabelEffectOptions, LabelEffectTool, LabelEffectLogic, LabelEffect | ||
+ | </pre> | ||
+ | |||
+ | <pre> | ||
+ | class TemplateKeyEffectOptions(LabelEffectOptions): | ||
+ | [...] | ||
+ | </pre> | ||
+ | |||
+ | ===Slicer 5.0: Python packaging dicom to pydicom=== | ||
+ | |||
+ | The [https://pypi.org/project/dicom/ dicom] python package has transitioned to become the [https://pypi.org/project/pydicom/ pydicom] python package. The dicom package is no longer included and all previous usages should be transitioned to use the pydicom package. See the [https://pydicom.github.io/pydicom/stable/transition_to_pydicom1.html Transition to pydicom 1.x] migration guide. | ||
+ | |||
+ | ===Slicer 4.9: Explicit include of ExternalProject module not needed anymore=== | ||
+ | |||
+ | Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26984 r26984], calling <tt>find_package(Slicer REQUIRED)</tt> and <tt>include(${Slicer_USE_FILE})</tt> ensure the <tt>ExternalProject</tt> CMake module is included. | ||
+ | |||
+ | Note that <tt>ExternalProjectDependency</tt> CMake module is also included. | ||
+ | |||
+ | ===Slicer 4.9: Explicit passing of CMAKE_OSX_* variables not needed anymore=== | ||
+ | |||
+ | Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26983 r26983], calling <tt>find_package(Slicer REQUIRED)</tt> and <tt>include(${Slicer_USE_FILE})</tt> initializes <tt>CMAKE_OSX_*</tt> variables and ensures the variables <tt>CMAKE_OSX_ARCHITECTURES</tt>, <tt>CMAKE_OSX_SYSROOT</tt> and <tt>CMAKE_OSX_DEPLOYMENT_TARGET</tt> are passed to all external projects when configuring SuperBuild based extension. | ||
+ | |||
===Slicer 4.9: Explicit initialization of CMAKE_BUILD_TYPE not needed anymore=== | ===Slicer 4.9: Explicit initialization of CMAKE_BUILD_TYPE not needed anymore=== | ||
Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26978 r26978], calling <tt>find_package(Slicer REQUIRED)</tt> and <tt>include(${Slicer_USE_FILE})</tt> initializes <tt>CMAKE_BUILD_TYPE</tt> and ensures the variables <tt>CMAKE_BUILD_TYPE</tt> and <tt>CMAKE_CONFIGURATION_TYPES</tt> are passed to all external projects when configuring SuperBuild based extension. | Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26978 r26978], calling <tt>find_package(Slicer REQUIRED)</tt> and <tt>include(${Slicer_USE_FILE})</tt> initializes <tt>CMAKE_BUILD_TYPE</tt> and ensures the variables <tt>CMAKE_BUILD_TYPE</tt> and <tt>CMAKE_CONFIGURATION_TYPES</tt> are passed to all external projects when configuring SuperBuild based extension. | ||
− | The module <tt>SlicerInitializeBuildType</tt> is automatically included in <tt> | + | The module <tt>SlicerInitializeBuildType</tt> is automatically included in <tt>UseSlicer</tt> CMake module. |
===Slicer 4.9: Subversion not required anymore=== | ===Slicer 4.9: Subversion not required anymore=== | ||
Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=27060 r27060], Subversion is not required anymore. | Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=27060 r27060], Subversion is not required anymore. | ||
+ | |||
+ | '''Example of commits''' | ||
+ | * [https://github.com/NIRALUser/SPHARM-PDM/commit/13373eb55374111805ce408ad942e4da2e909cff NIRALUser/SPHARM-PDM@13373eb55]: cmake: Remove unneeded SVN requirement | ||
===Slicer 4.9: Support EP_GIT_PROTOCOL and use of ExternalProject_SetIfNotDefined for setting GIT_REPOSITORY, GIT_TAG and alike=== | ===Slicer 4.9: Support EP_GIT_PROTOCOL and use of ExternalProject_SetIfNotDefined for setting GIT_REPOSITORY, GIT_TAG and alike=== | ||
Line 37: | Line 310: | ||
===Slicer 4.9: Use ExternalProject_AlwaysConfigure to force reconfigure of inner project=== | ===Slicer 4.9: Use ExternalProject_AlwaysConfigure to force reconfigure of inner project=== | ||
− | Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26551 r26551], the function <tt>ExternalProject_AlwaysConfigure<tt> may be used to ensure the inner project is always reconfigured. | + | Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26551 r26551], the function <tt>ExternalProject_AlwaysConfigure</tt> may be used to ensure the inner project is always reconfigured. |
Using the `BUILD_ALWAYS` option supported by <tt>ExternalProject_Add</tt> will not have the intended effect. | Using the `BUILD_ALWAYS` option supported by <tt>ExternalProject_Add</tt> will not have the intended effect. | ||
Line 43: | Line 316: | ||
See https://cmake-artichoke.readthedocs.io/en/latest/ExternalProjectDependency.html#function:ExternalProject_AlwaysConfigure | See https://cmake-artichoke.readthedocs.io/en/latest/ExternalProjectDependency.html#function:ExternalProject_AlwaysConfigure | ||
− | ===Slicer 4.9: Specifying external | + | ===Slicer 4.9: Specifying external projects to install in SuperBuild extension=== |
Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=27267 r27267] and [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=27232 r27232], the following should be used to ensure | Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=27267 r27267] and [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=27232 r27232], the following should be used to ensure | ||
Line 59: | Line 332: | ||
include(${Slicer_EXTENSION_GENERATE_CONFIG}) | include(${Slicer_EXTENSION_GENERATE_CONFIG}) | ||
include(${Slicer_EXTENSION_CPACK}) | include(${Slicer_EXTENSION_CPACK}) | ||
+ | </pre> | ||
+ | |||
+ | ===Slicer 4.9: Generating (Extension)Config.cmake=== | ||
+ | |||
+ | Initially introduced in [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=25944 r25944], and later improved in [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=25991 r25991], including <tt>${Slicer_EXTENSION_GENERATE_CONFIG}</tt> ensure a config is generated and allow an extension to import targets from another extension by using <tt>find_package(ExtensionName REQUIRED)</tt>. | ||
+ | |||
+ | <pre> | ||
+ | [...] | ||
+ | |||
+ | include(${Slicer_EXTENSION_GENERATE_CONFIG}) | ||
+ | include(${Slicer_EXTENSION_CPACK}) | ||
+ | </pre> | ||
+ | |||
+ | ===Slicer 4.9: Initializing <projectName>_BUILD_SLICER_EXTENSION option: Standalone vs Slicer extension build=== | ||
+ | |||
+ | The following snippet allows to automatically initialize <tt><projectName>_BUILD_SLICER_EXTENSION</tt> to <tt>ON</tt> if <tt>Slicer_DIR</tt> is defined. | ||
+ | |||
+ | <pre> | ||
+ | #----------------------------------------------------------------------------- | ||
+ | # Standalone vs Slicer extension option | ||
+ | #----------------------------------------------------------------------------- | ||
+ | |||
+ | # This option should be named after the project name, it corresponds to the | ||
+ | # option set to ON when the project is build by the Slicer Extension build | ||
+ | # system. | ||
+ | |||
+ | set(_default OFF) | ||
+ | set(_reason "${PROJECT_NAME}_BUILD_SLICER_EXTENSION is ON") | ||
+ | if(NOT DEFINED ${PROJECT_NAME}_BUILD_SLICER_EXTENSION AND DEFINED Slicer_DIR) | ||
+ | set(_default ON) | ||
+ | set(_reason "Slicer_DIR is SET") | ||
+ | endif() | ||
+ | |||
+ | option(${PROJECT_NAME}_BUILD_SLICER_EXTENSION "Build as a Slicer Extension" ${_default}) | ||
+ | |||
+ | set(_msg "Checking if building as a Slicer extension") | ||
+ | message(STATUS ${_msg}) | ||
+ | if(${PROJECT_NAME}_BUILD_SLICER_EXTENSION) | ||
+ | message(STATUS "${_msg} - yes (${_reason})") | ||
+ | else() | ||
+ | message(STATUS "${_msg} - no (${PROJECT_NAME}_BUILD_SLICER_EXTENSION is OFF)") | ||
+ | endif() | ||
+ | mark_as_superbuild(${PROJECT_NAME}_BUILD_SLICER_EXTENSION:BOOL) | ||
</pre> | </pre> |
Latest revision as of 14:51, 22 March 2022
Home < Documentation < Nightly < Developers < Tutorials < MigrationGuide < SlicerExtensionContents
- 1 Slicer Extension updates
- 1.1 Slicer 5.0: Supporting both VTK 8.0 and VTK 9.0
- 1.2 Slicer 5.0: ITKv4 to ITKv5
- 1.3 Slicer 5.0: Python2 to Python3
- 1.4 Slicer 5.0: Python2 to Python3 (EditorEffect imports)
- 1.5 Slicer 5.0: Python packaging dicom to pydicom
- 1.6 Slicer 4.9: Explicit include of ExternalProject module not needed anymore
- 1.7 Slicer 4.9: Explicit passing of CMAKE_OSX_* variables not needed anymore
- 1.8 Slicer 4.9: Explicit initialization of CMAKE_BUILD_TYPE not needed anymore
- 1.9 Slicer 4.9: Subversion not required anymore
- 1.10 Slicer 4.9: Support EP_GIT_PROTOCOL and use of ExternalProject_SetIfNotDefined for setting GIT_REPOSITORY, GIT_TAG and alike
- 1.11 Slicer 4.9: Use ExternalProject_AlwaysConfigure to force reconfigure of inner project
- 1.12 Slicer 4.9: Specifying external projects to install in SuperBuild extension
- 1.13 Slicer 4.9: Generating (Extension)Config.cmake
- 1.14 Slicer 4.9: Initializing <projectName>_BUILD_SLICER_EXTENSION option: Standalone vs Slicer extension build
Slicer Extension updates
Slicer 5.0: Supporting both VTK 8.0 and VTK 9.0
Transition from VTK 8.0 to VTK 9.0
See Documentation/Nightly/Developers/Tutorials/MigrationGuide#Transition_from_VTK_8.0_to_VTK_9.0
Remove building of vtk*PythonD library
With VTK >= 8.90, the vtk*Python
and vtk*Python
libraries were merged together.
To fix error messages similar to:
CMake Error at MarginCalculatorCommon/CMakeLists.txt:70 (set_target_properties): set_target_properties Can not find target to add properties to: vtkMarginCalculatorCommonPythonD
The code associated with the PythonD target could be removed to support VTK >= 8.90, or it could be conditionally excluded to support older version of VTK.
References
- Slicer c658b7b42 ENH: Add support for building against VTK 8.2.0 or 9.0.0
Slicer 5.0: ITKv4 to ITKv5
To remove support for ITKv4 and only support ITKv5. See Documentation/Nightly/Developers/Tutorials/MigrationGuide#Transition_from_ITK4_to_ITK5, it includes the following sections:
- Upgrading to ITKv5 or keep using ITKv4 GenerateThreadedData
- itkMultiThreader refactor
- SimpleFastMutexLock, FastMutexLock and MutexLock are deprecated
If completely removing support for ITKv4 and only supporting ITKv5 is not possible. It is possible to conditionally include the ITKv4 code.
For example:
#if ITK_VERSION_MAJOR >= 5 itk::ITK_THREAD_RETURN_TYPE #else ITK_THREAD_RETURN_TYPE #endif
Example of commits:
- ResampleDTIlogEuclidean
- ResampleDTIlogEuclidean@f779bf7 COMP: Use std::mutex instead of deprecated ITK implementation
- ResampleDTIlogEuclidean@ed5093b BUG: ITKv5: Fix tests updating ITK filters to use ITKv5 dynamic multi-threading
- PETTumorSegmentation
- PETTumorSegmentation PR#18 BUG: Add support for ITKv5 dynamic multithreader
- PETTumorSegmentation PR#18 COMP: Support ITKv5 refactored threading models
Slicer 5.0: Python2 to Python3
Depending on the complexity of the extension, two approaches shall be considered:
- code base common to Slicer 4.10 and Slicer 5.0. This means backward compatibility with the latest release is maintained.
- specific branch for each Slicer version (e.g master-4.10 and master)
Example of commits
- Slicer r28079 STYLE: Update python classes to follow new-style
- MultiVolumeImporter@f9917b2 STYLE: Apply lib2to3.fixes.fix_idioms to support python3
- MultiVolumeImporter@3edd1bc ENH: Support for Python3
- ShapeVariationAnalyzer@4234377 STYLE: Update python scripts for python 3.x
- PETTumorSegmentation PR#18 BUG: Add support for Python 3
Step 1
Understanding the scope of changes needed to support Python 3 can be done by:
- installing future package (see https://python-future.org/)
Slicer_DIR=/path/to/Slicer-SuperBuild/Slicer-build ${Slicer_DIR}/../python-install/bin/PythonSlicer -m pip install future
- applying all fixes
for f in `find ./ -name "*.py"`; do \ ${Slicer_DIR}/../python-install/bin/PythonSlicer \ --launch futurize --nobackups --write $f; \ done
Alternatively the future package could be installed in a regular python environment and used from there.
for f in `find ./ -name "*.py"`; do \ futurize --nobackups --write $f; \ done
This first step will apply the following transformations:
lib2to3.fixes.fix_apply lib2to3.fixes.fix_dict lib2to3.fixes.fix_except lib2to3.fixes.fix_exec lib2to3.fixes.fix_exitfunc lib2to3.fixes.fix_filter lib2to3.fixes.fix_funcattrs lib2to3.fixes.fix_getcwdu lib2to3.fixes.fix_has_key lib2to3.fixes.fix_input lib2to3.fixes.fix_intern lib2to3.fixes.fix_isinstance lib2to3.fixes.fix_itertools lib2to3.fixes.fix_itertools_imports lib2to3.fixes.fix_long lib2to3.fixes.fix_map lib2to3.fixes.fix_methodattrs lib2to3.fixes.fix_ne lib2to3.fixes.fix_next lib2to3.fixes.fix_nonzero lib2to3.fixes.fix_numliterals lib2to3.fixes.fix_operator lib2to3.fixes.fix_paren lib2to3.fixes.fix_raw_input lib2to3.fixes.fix_reduce lib2to3.fixes.fix_renamesSlicer migration guide describes how to update the code. See https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/MigrationGuide/SlicerExtension#Slicer_5.0:_Python2_to_Python3 lib2to3.fixes.fix_repr lib2to3.fixes.fix_standarderror lib2to3.fixes.fix_sys_exc lib2to3.fixes.fix_throw lib2to3.fixes.fix_tuple_params lib2to3.fixes.fix_types lib2to3.fixes.fix_xreadlines lib2to3.fixes.fix_zip libfuturize.fixes.fix_absolute_import libfuturize.fixes.fix_basestring libfuturize.fixes.fix_cmp libfuturize.fixes.fix_division_safe libfuturize.fixes.fix_execfile libfuturize.fixes.fix_future_builtins libfuturize.fixes.fix_future_standard_library libfuturize.fixes.fix_future_standard_library_urllib libfuturize.fixes.fix_metaclass libfuturize.fixes.fix_next_call libfuturize.fixes.fix_object libfuturize.fixes.fix_print_with_import libfuturize.fixes.fix_raise libfuturize.fixes.fix_unicode_keep_u libfuturize.fixes.fix_xrange_with_import libpasteurize.fixes.fix_newstyle
expect these two:
lib2to3.fixes.fix_idioms lib2to3.fixes.fix_ws_comma
If the number of changes is large, you should consider applying each fixes independently.
Step 2
Not all changes applied automatically should be integrated. Most of the changes introducing imports from the future python package can simply be removed or removed after making use of try/except or check of sys.version_info[0].
- Systematic conversion of keys, values or items from dictionaries do not need to be systematically converted from dict_keys/dict_values/dict_items to list. For example, this Slicer r28077 reverted some of the automatic changes applied by the future CLI.
- Unless python classes implement the object functions next and __unicode__ specific to Python 2, nothing specific should be done and from builtins import object can be removed. Automatic removal of imports can also be automated doing:
for f in `find ./ -name "*.py"`; do \ sed -i '/from builtins import object/ d' $f; \ done
- Unless there are performances issue associated with using range in Python 2, the from builtins import range can be removed:
for f in `find ./ -name "*.py"`; do \ sed -i '/from builtins import range/ d' $f; \ done
- If there are performance issue with using range in Python 2, the following could also be done:
import sys if sys.version_info[0] == 2: range = xrange
- Use of aliases can also be avoided by removing
from future import standard_library standard_library.install_aliases()
and instead doing something like this:
try: import queue except ImportError: import Queue as queue
For a complete list aliases, see https://python-future.org/reference.html#module-future.standard_library
- Use of old_div() function can generally be avoided by using int()
Step 3
The lib2to3.fixes.fix_idioms transformation should explicitly be applied:
for f in `find ./ -name "*.py"`; do \ ${Slicer_DIR}/../python-install/bin/PythonSlicer \ --launch futurize -f lib2to3.fixes.fix_idioms --nobackups --write $f; \ done
Slicer 5.0: Python2 to Python3 (EditorEffect imports)
Error:
from EditorLib import EditorLib ImportError: cannot import name 'EditorLib'
Import of Editor classes should be updated. For example, see r28122.
Before:
import EditorLib from EditorLib.EditOptions import HelpButton from EditorLib.EditOptions import EditOptions from EditorLib import EditUtil
class TemplateKeyEffectOptions(EditorLib.LabelEffectOptions): [...]
After:
import EditorLib from EditorLib import EditOptions, HelpButton from EditorLib import EditUtil from EditorLib import LabelEffectOptions, LabelEffectTool, LabelEffectLogic, LabelEffect
class TemplateKeyEffectOptions(LabelEffectOptions): [...]
Slicer 5.0: Python packaging dicom to pydicom
The dicom python package has transitioned to become the pydicom python package. The dicom package is no longer included and all previous usages should be transitioned to use the pydicom package. See the Transition to pydicom 1.x migration guide.
Slicer 4.9: Explicit include of ExternalProject module not needed anymore
Following r26984, calling find_package(Slicer REQUIRED) and include(${Slicer_USE_FILE}) ensure the ExternalProject CMake module is included.
Note that ExternalProjectDependency CMake module is also included.
Slicer 4.9: Explicit passing of CMAKE_OSX_* variables not needed anymore
Following r26983, calling find_package(Slicer REQUIRED) and include(${Slicer_USE_FILE}) initializes CMAKE_OSX_* variables and ensures the variables CMAKE_OSX_ARCHITECTURES, CMAKE_OSX_SYSROOT and CMAKE_OSX_DEPLOYMENT_TARGET are passed to all external projects when configuring SuperBuild based extension.
Slicer 4.9: Explicit initialization of CMAKE_BUILD_TYPE not needed anymore
Following r26978, calling find_package(Slicer REQUIRED) and include(${Slicer_USE_FILE}) initializes CMAKE_BUILD_TYPE and ensures the variables CMAKE_BUILD_TYPE and CMAKE_CONFIGURATION_TYPES are passed to all external projects when configuring SuperBuild based extension.
The module SlicerInitializeBuildType is automatically included in UseSlicer CMake module.
Slicer 4.9: Subversion not required anymore
Following r27060, Subversion is not required anymore.
Example of commits
- NIRALUser/SPHARM-PDM@13373eb55: cmake: Remove unneeded SVN requirement
Slicer 4.9: Support EP_GIT_PROTOCOL and use of ExternalProject_SetIfNotDefined for setting GIT_REPOSITORY, GIT_TAG and alike
Following r26957, extension may use the following convention to define GIT_REPOSITORY and GIT_TAG, this allows developer to override the value before the first configuration by setting the corresponding environment variable, or by explicitly configuring the project with that variable.
The option EP_GIT_PROTOCOL is also already set in ExternalProjectDependency module included by Slicer and its value is updated based on the <SUPERBUILD_TOPLEVEL_PROJECT>_USE_GIT_PROTOCOL option.
ExternalProject_SetIfNotDefined( ${CMAKE_PROJECT_NAME}_${proj}_GIT_REPOSITORY "${EP_GIT_PROTOCOL}://github.com/jcfr/shape4D.git" QUIET ) ExternalProject_SetIfNotDefined( ${CMAKE_PROJECT_NAME}_${proj}_GIT_TAG "12fef84ca2a56feffc59d8159bdadd2ce4a4138e" # slicersalt-2018-01-22-c74c766a4c QUIET )
See:
- https://cmake-artichoke.readthedocs.io/en/latest/ExternalProjectDependency.html#variable:EP_GIT_PROTOCOL
- https://cmake-artichoke.readthedocs.io/en/latest/ExternalProjectDependency.html#function:ExternalProject_SetIfNotDefined
Slicer 4.9: Use ExternalProject_AlwaysConfigure to force reconfigure of inner project
Following r26551, the function ExternalProject_AlwaysConfigure may be used to ensure the inner project is always reconfigured.
Using the `BUILD_ALWAYS` option supported by ExternalProject_Add will not have the intended effect.
Slicer 4.9: Specifying external projects to install in SuperBuild extension
Following r27267 and r27232, the following should be used to ensure the extension can also be bundled into a Slicer custom application. When bundled, the variable ${EXTENSION_NAME}_CPACK_INSTALL_CMAKE_PROJECTS is then used to update the application's list of project to install.
#----------------------------------------------------------------------------- set(EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS) #list(APPEND EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS "${Foo_DIR};Foo;RuntimeLibraries;/") set(${EXTENSION_NAME}_CPACK_INSTALL_CMAKE_PROJECTS "${EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS}" CACHE STRING "List of external projects to install" FORCE) #----------------------------------------------------------------------------- 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_EXTENSION_CPACK})
Slicer 4.9: Generating (Extension)Config.cmake
Initially introduced in r25944, and later improved in r25991, including ${Slicer_EXTENSION_GENERATE_CONFIG} ensure a config is generated and allow an extension to import targets from another extension by using find_package(ExtensionName REQUIRED).
[...] include(${Slicer_EXTENSION_GENERATE_CONFIG}) include(${Slicer_EXTENSION_CPACK})
Slicer 4.9: Initializing <projectName>_BUILD_SLICER_EXTENSION option: Standalone vs Slicer extension build
The following snippet allows to automatically initialize <projectName>_BUILD_SLICER_EXTENSION to ON if Slicer_DIR is defined.
#----------------------------------------------------------------------------- # Standalone vs Slicer extension option #----------------------------------------------------------------------------- # This option should be named after the project name, it corresponds to the # option set to ON when the project is build by the Slicer Extension build # system. set(_default OFF) set(_reason "${PROJECT_NAME}_BUILD_SLICER_EXTENSION is ON") if(NOT DEFINED ${PROJECT_NAME}_BUILD_SLICER_EXTENSION AND DEFINED Slicer_DIR) set(_default ON) set(_reason "Slicer_DIR is SET") endif() option(${PROJECT_NAME}_BUILD_SLICER_EXTENSION "Build as a Slicer Extension" ${_default}) set(_msg "Checking if building as a Slicer extension") message(STATUS ${_msg}) if(${PROJECT_NAME}_BUILD_SLICER_EXTENSION) message(STATUS "${_msg} - yes (${_reason})") else() message(STATUS "${_msg} - no (${PROJECT_NAME}_BUILD_SLICER_EXTENSION is OFF)") endif() mark_as_superbuild(${PROJECT_NAME}_BUILD_SLICER_EXTENSION:BOOL)