Difference between revisions of "Documentation/Nightly/Developers/Tutorials/MigrationGuide/SlicerExtension"

From Slicer Wiki
Jump to: navigation, search
(Created page with "<noinclude>__TOC__</noinclude> ==Slicer Extension updates== ===Slicer 4.9: Explicit initialization of CMAKE_BUILD_TYPE not needed anymore=== Following [http://viewvc.slicer.o...")
 
Tag: 2017 source edit
 
(48 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>UserSlicer</tt>.
+
The module <tt>SlicerInitializeBuildType</tt> is automatically included in <tt>UseSlicer</tt> CMake module.
 +
 
 +
===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.
 +
 
 +
'''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===
 +
 
 +
Following [http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=26957 r26957], extension may use the following convention to define <tt>GIT_REPOSITORY</tt> and <tt>GIT_TAG</tt>, 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 <tt>EP_GIT_PROTOCOL</tt> is also already set in <tt>ExternalProjectDependency</tt> module included by Slicer and its value is updated based on the <tt>&lt;SUPERBUILD_TOPLEVEL_PROJECT&gt;_USE_GIT_PROTOCOL</tt> option.
 +
 
 +
<pre>
 +
  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
 +
    )
 +
</pre>
 +
 
 +
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 [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.
 +
 
 +
See https://cmake-artichoke.readthedocs.io/en/latest/ExternalProjectDependency.html#function:ExternalProject_AlwaysConfigure
 +
 
 +
===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
 +
the extension can also be bundled into a Slicer custom application. When bundled, the variable <tt>${EXTENSION_NAME}_CPACK_INSTALL_CMAKE_PROJECTS</tt> is then used to update the application's list of project to install. 
 +
 
 +
<pre>
 +
#-----------------------------------------------------------------------------
 +
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})
 +
</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>

Latest revision as of 14:51, 22 March 2022

Home < Documentation < Nightly < Developers < Tutorials < MigrationGuide < SlicerExtension

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 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:

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:

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


Step 1

Understanding the scope of changes needed to support Python 3 can be done by:

  1. 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
    
  2. applying all fixes
      for f in `find ./ -name "*.py"`; do \
        ${Slicer_DIR}/../python-install/bin/PythonSlicer \
          --launch futurize --nobackups --write $f; \
      done
    

    Note 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

Note 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

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:

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.

See https://cmake-artichoke.readthedocs.io/en/latest/ExternalProjectDependency.html#function:ExternalProject_AlwaysConfigure

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)