From 076f64b2f48e30ad77c08e661bb08078de09b00f Mon Sep 17 00:00:00 2001
From: Stefan Bienert <stefan.bienert@unibas.ch>
Date: Thu, 16 Oct 2014 09:16:55 +0200
Subject: [PATCH] Refurbished documentation for meld, fixed doctest issues

---
 CMakeLists.txt              |   8 +-
 cmake_support/PROMOD3.cmake | 248 +++++++++++++++++++++---------------
 doc/CMakeLists.txt          |  31 +++--
 extras/pre-commit           |  10 +-
 meld/doc/CMakeLists.txt     |   1 -
 meld/doc/index.rst          |  98 +++++++++++++-
 meld/doc/rawmodel.rst       |  80 ------------
 7 files changed, 265 insertions(+), 211 deletions(-)
 delete mode 100644 meld/doc/rawmodel.rst

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 39c0db72..426e32ad 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,7 +16,8 @@ include(PROMOD3)
 set(PROMOD3_VERSION_MAJOR 0)
 set(PROMOD3_VERSION_MINOR 1)
 set(PROMOD3_VERSION_PATCH 0)
-set(PROMOD3_VERSION_STRING ${PROMOD3_VERSION_MAJOR}.${PROMOD3_VERSION_MINOR}.${PROMOD3_VERSION_PATCH})
+set(PROMOD3_VERSION_STRING ${PROMOD3_VERSION_MAJOR}.${PROMOD3_VERSION_MINOR})
+set(PROMOD3_VERSION_STRING ${PROMOD3_VERSION_STRING}.${PROMOD3_VERSION_PATCH})
 
 option(DISABLE_DOCUMENTATION "Do not build documentation" OFF)
 option(DISABLE_DISABLE_DOCTEST "Do not check examples in documentation" OFF)
@@ -85,6 +86,11 @@ if(NOT EIGEN3_FOUND)
   message(FATAL_ERROR "Eigen3 is essential for building ${PROJECT_NAME}.")
 endif()
 
+# This is somewhat experimental: Checking if Boost is compiled with the same
+# Python version used for Promod3. The very same macro is disabled in OST so
+# it may fail at some point.
+promod3_match_boost_python_version(${PYTHON_LIBRARIES})
+
 # basic environment
 include_directories(${Boost_INCLUDE_DIRS}
                     ${OST_INCLUDE_DIR}
diff --git a/cmake_support/PROMOD3.cmake b/cmake_support/PROMOD3.cmake
index 4f52adfb..ef12c004 100644
--- a/cmake_support/PROMOD3.cmake
+++ b/cmake_support/PROMOD3.cmake
@@ -130,8 +130,8 @@ endmacro()
 #-------------------------------------------------------------------------------
 # parse_file_list
 #
-# this macro splits a list of files with IN_DIR statements and fills them into a map
-# where the key is the directory name
+# this macro splits a list of files with IN_DIR statements and fills them into
+# a map where the key is the directory name
 #-------------------------------------------------------------------------------
 macro(parse_file_list FILELIST FILEMAP)
   set(_EXPECT_IN_DIR FALSE)
@@ -195,10 +195,14 @@ macro(module)
   file(MAKE_DIRECTORY ${LIBEXEC_STAGE_PATH})
   file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
   if(NOT TARGET create_stage)
-    add_custom_target(create_stage COMMAND ${CMAKE_COMMAND} -E make_directory ${LIB_STAGE_PATH}
-                                   COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
-                                   COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBEXEC_STAGE_PATH}
-                                   COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/tests")
+    add_custom_target(create_stage COMMAND ${CMAKE_COMMAND} -E make_directory
+                                           ${LIB_STAGE_PATH}
+                                   COMMAND ${CMAKE_COMMAND} -E make_directory
+                                           ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+                                   COMMAND ${CMAKE_COMMAND} -E make_directory
+                                           ${LIBEXEC_STAGE_PATH}
+                                   COMMAND ${CMAKE_COMMAND} -E make_directory
+                                           "${CMAKE_BINARY_DIR}/tests")
   endif()
   if (_ARG_SOURCES)
     # when there is at least one source file, we build a library
@@ -226,7 +230,8 @@ macro(module)
                           COMPILE_DEFINITIONS PROMOD3_MODULE_${_UPPER_LIB_NAME})
     set_target_properties(${_LIB_NAME} PROPERTIES
                           VERSION ${PROMOD3_VERSION_STRING}
-                          SOVERSION ${PROMOD3_VERSION_MAJOR}.${PROMOD3_VERSION_MINOR})    
+                          SOVERSION
+                              ${PROMOD3_VERSION_MAJOR}.${PROMOD3_VERSION_MINOR})
     set_target_properties(${_LIB_NAME} PROPERTIES
                           LIBRARY_OUTPUT_DIRECTORY ${LIB_STAGE_PATH}
                           ARCHIVE_OUTPUT_DIRECTORY ${LIB_STAGE_PATH}
@@ -246,7 +251,8 @@ macro(module)
     endif()
     foreach(_DEPENDENCY ${_ARG_DEPENDS_ON})
       get_property(target_type TARGET ${_DEPENDENCY} PROPERTY TYPE)
-      if(target_type MATCHES "STATIC_LIBRARY|MODULE_LIBRARY|SHARED_LIBRARY|EXECUTABLE")
+      if(target_type MATCHES
+                      "STATIC_LIBRARY|MODULE_LIBRARY|SHARED_LIBRARY|EXECUTABLE")
         target_link_libraries(${_LIB_NAME} ${_DEPENDENCY})
       else()
         add_dependencies(${_LIB_NAME} ${_DEPENDENCY})
@@ -265,7 +271,8 @@ macro(module)
   # stage headers  
   #-----------------------------------------------------------------------------
   if (_ARG_HEADERS)
-    stage_and_install_headers("${_ARG_HEADERS}" "${_HEADER_OUTPUT_DIR}" "${_LIB_NAME}")
+    stage_and_install_headers("${_ARG_HEADERS}" "${_HEADER_OUTPUT_DIR}"
+                              "${_LIB_NAME}")
   endif()
 endmacro()
 
@@ -287,7 +294,8 @@ macro(stage_and_install_headers HEADERLIST HEADER_OUTPUT_DIR TARGET)
     endforeach()
     set(_HDR_STAGE_DIR "${HEADER_OUTPUT_DIR}/${_DIR}")
     set(_FULL_HEADER_DIR "${HEADER_STAGE_PATH}/${_HDR_STAGE_DIR}")
-    copy_if_different("" "${_FULL_HEADER_DIR}" "${_ABS_HEADER_NAMES}" "" "${TARGET}_headers")
+    copy_if_different("" "${_FULL_HEADER_DIR}" "${_ABS_HEADER_NAMES}" ""
+                      "${TARGET}_headers")
     install(FILES ${_ABS_HEADER_NAMES} DESTINATION "include/${_HDR_STAGE_DIR}")
   endforeach()
 endmacro()
@@ -323,7 +331,8 @@ macro(executable)
       if (PROMOD3_GCC_45)    
         set_target_properties(${_ARG_NAME}
                               PROPERTIES LINK_SEARCH_END_STATIC TRUE  
-                              LINK_FLAGS "-static-libgcc -static-libstdc++ -static -pthread")
+                              LINK_FLAGS
+                            "-static-libgcc -static-libstdc++ -static -pthread")
       else()
         set_target_properties(${_ARG_NAME}
                               PROPERTIES LINK_SEARCH_END_STATIC TRUE  
@@ -363,7 +372,8 @@ macro(executable_libexec)
       set_target_properties(${_ARG_NAME} PROPERTIES
                             LINK_FLAGS "-Wl,-rpath,@loader_path/../../lib")
     elseif (UNIX)
-      set_target_properties(${_ARG_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN/../../${LIB_DIR}")
+      set_target_properties(${_ARG_NAME} PROPERTIES INSTALL_RPATH
+                                                     "$ORIGIN/../../${LIB_DIR}")
     endif (APPLE)
   endif (NOT _ARG_NO_RPATH AND NOT _ARG_STATIC)
   if (_ARG_LINK)
@@ -422,13 +432,15 @@ macro(script)
   endif()
   if (_ARG_SUBSTITUTE)
     if (NOT _ARG_INPUT)
-      message(FATAL_ERROR "script() can only substitute when INPUT is present.")    
+      message(FATAL_ERROR "script() can only substitute when INPUT is present.")
     endif()
 
-    substitute(IN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${_INPUT}" OUT_FILE ${_ARG_NAME} 
+    substitute(IN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${_INPUT}"
+               OUT_FILE ${_ARG_NAME}
                DICT ${_ARG_SUBSTITUTE})
   endif()
-  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_ARG_NAME} DESTINATION ${_ARG_OUTPUT_DIR} 
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_ARG_NAME}
+          DESTINATION ${_ARG_OUTPUT_DIR}
           PERMISSIONS WORLD_EXECUTE GROUP_EXECUTE OWNER_EXECUTE 
                       WORLD_READ GROUP_READ OWNER_READ)
   copy_if_different("./" "${STAGE_DIR}/${_ARG_OUTPUT_DIR}" 
@@ -436,65 +448,6 @@ macro(script)
   add_dependencies(${_ARG_TARGET} subst_${_ARG_NAME})
 endmacro()
 
-#-------------------------------------------------------------------------------
-# Synopsis:
-#   ui_to_python(libname stagedir[input_file1 ...])
-# Description:
-#   Calls pyuic on every input file. The resulting python files are stored in
-#   the variable with name out_files.
-#-------------------------------------------------------------------------------
-macro(ui_to_python LIBNAME PYMODDIR STAGEDIR)
-  set(_input_files ${ARGN})
-  add_custom_target("${LIBNAME}_ui" ALL)
-  add_dependencies("_${LIBNAME}" "${LIBNAME}_ui")
-  find_program(_PYUIC_EXECUTABLE
-    NAMES pyuic4-${PYTHON_VERSION} pyuic4 pyuic pyuic4.bat
-    PATHS  ENV PATH 
-  )  
-  if(NOT _PYUIC_EXECUTABLE)
-    message(FATAL_ERROR "Could not find pyuic command in " ${QT_BINARY_DIR} " for python version " ${PYTHON_VERSION})
-  endif(NOT _PYUIC_EXECUTABLE)
-  set(out_files)
-  foreach(input_file ${_input_files})
-    get_filename_component(_out_file ${input_file} NAME_WE)
-    get_filename_component(_in_file ${input_file} ABSOLUTE)
-    set(_out_file ${_out_file}_ui.py)
-    set(_abs_out_file ${STAGEDIR}/${_out_file})
-    add_custom_command(TARGET ${LIBNAME}_ui
-                       COMMAND ${_PYUIC_EXECUTABLE} -o ${_abs_out_file} ${_in_file}
-                       VERBATIM DEPENDS ${input_file}
-                       )
-    list(APPEND out_files ${_abs_out_file})
-  endforeach()
-  compile_py_files(_${LIBNAME} ${STAGEDIR} compiled_files ${out_files})
-  install(FILES ${out_files} DESTINATION "${LIB_DIR}/${PYMODDIR}")
-  install(FILES ${compiled_files} DESTINATION "${LIB_DIR}/${PYMODDIR}")
-endmacro()
-
-#-------------------------------------------------------------------------------
-# Synopsis:
-#   compile_py_files(module out_dir compiled_files [input_file1 ...])
-# Description:
-#   Calls pyuic on every input file. The resulting python files are stored in
-#   the variable with name compiled_files.
-#-------------------------------------------------------------------------------
-macro(compile_py_files module out_dir compiled_files_name)
-  set(_input_files ${ARGN})
-  set(${compiled_files_name})
-  foreach(input_file ${_input_files})
-    get_filename_component(_out_file ${input_file} NAME_WE)
-    get_filename_component(_in_file ${input_file} ABSOLUTE)
-    set(_out_file ${out_dir}/${_out_file}.pyc)
-    list(APPEND ${compiled_files_name} ${_out_file})
-    get_filename_component(_in_name ${input_file} NAME)
-    file(MAKE_DIRECTORY  ${out_dir})
-    add_custom_command(TARGET ${module}
-                       COMMAND ${PYTHON_BINARY} -c "import py_compile;py_compile.compile(\"${_in_file}\",\"${_out_file}\",\"${_in_name}\",doraise=True)"
-                       VERBATIM DEPENDS ${input_file}
-                       )
-  endforeach()
-endmacro()
-
 #-------------------------------------------------------------------------------
 # Synopsis:
 #   pymod(NAME name CPP source1 source2 PY source source2 [IN_DIR dir] 
@@ -521,7 +474,8 @@ macro(pymod)
   if (_ARG_OUTPUT_DIR)
     set(PYMOD_DIR "python${PYTHON_VERSION}/site-packages/${_ARG_OUTPUT_DIR}")
   else()
-    set(PYMOD_DIR "python${PYTHON_VERSION}/site-packages/${_ARG_PREFIX}/${_ARG_NAME}")
+    set(PYMOD_DIR
+        "python${PYTHON_VERSION}/site-packages/${_ARG_PREFIX}/${_ARG_NAME}")
   endif()
   set(PYMOD_STAGE_DIR "${LIB_STAGE_PATH}/${PYMOD_DIR}")
   file(MAKE_DIRECTORY ${PYMOD_STAGE_DIR})
@@ -541,12 +495,12 @@ macro(pymod)
     target_link_libraries("_${_ARG_NAME}" ${_PARENT_LIB_NAME} 
                           ${PYTHON_LIBRARIES} ${BOOST_PYTHON_LIBRARIES})
     set_target_properties("_${_ARG_NAME}"
-                          PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PYMOD_STAGE_DIR})
+                         PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PYMOD_STAGE_DIR})
     if (NOT ENABLE_STATIC)
       if (_USE_RPATH)
         string(REGEX REPLACE "/[^/]*" "/.." inv_pymod_path "/${PYMOD_DIR}")
         set_target_properties("_${_ARG_NAME}"
-                              PROPERTIES INSTALL_RPATH "$ORIGIN${inv_pymod_path}/")
+                           PROPERTIES INSTALL_RPATH "$ORIGIN${inv_pymod_path}/")
       else()
         set_target_properties("_${_ARG_NAME}"
                               PROPERTIES INSTALL_RPATH "")
@@ -573,6 +527,7 @@ macro(pymod)
   else()
     add_custom_target("_${_ARG_NAME}" ALL)
   endif()
+  add_to_pymod_list(MOD "_${_ARG_NAME}")
   #-----------------------------------------------------------------------------
   # compile python files
   #-----------------------------------------------------------------------------
@@ -595,17 +550,16 @@ macro(pymod)
                   "${LIB_DIR}/${PYMOD_DIR}/${_DIR}")
           string(REPLACE "/" "_" _DIR_NO_SLASH "${_DIR}")
           add_custom_target("${_ARG_NAME}_${_DIR_NO_SLASH}_pymod" ALL)
-          add_dependencies("_${_ARG_NAME}" "${_ARG_NAME}_${_DIR_NO_SLASH}_pymod")
+          add_dependencies("_${_ARG_NAME}"
+                           "${_ARG_NAME}_${_DIR_NO_SLASH}_pymod")
           copy_if_different("./" "${PYMOD_STAGE_DIR}/${_DIR}" "${_ABS_PY_FILES}"
                             TARGETS "${_ARG_NAME}_${_DIR_NO_SLASH}_pymod")
           if(NOT DISABLE_DOCUMENTATION)
-            # create special list: module_name_ind_dir (or similar)
-            # if list exists, extend!
-            # in RST iteration, check if such a list exists
             # add deps
-            add_doc_dependency(NAME ${_ARG_NAME} DEP "${_ARG_NAME}_${_DIR_NO_SLASH}_pymod")
+            add_doc_dependency(NAME ${_ARG_NAME}
+                               DEP "${_ARG_NAME}_${_DIR_NO_SLASH}_pymod")
             add_doc_dependency(NAME ${_ARG_NAME} DEP "${_ABS_PY_FILES}")
-            add_module_name(MOD "${_ARG_NAME}_${_DIR_NO_SLASH}_pymod")
+            add_py_mod_src(MOD "${_ARG_NAME}_${_DIR_NO_SLASH}_pymod")
           endif()
           set(_PY_FILES)
         else()
@@ -634,13 +588,14 @@ macro(pymod)
       endforeach()
     endif()
   endif()
+
   #-----------------------------------------------------------------------------
   # sphinx documentation
   #-----------------------------------------------------------------------------
   if(NOT DISABLE_DOCUMENTATION)
     add_doc_dependency(NAME ${_ARG_NAME} DEP "${_ARG_NAME}_pymod")
     add_doc_dependency(NAME ${_ARG_NAME} DEP "${_ABS_PY_FILES}")
-    add_module_name(MOD "${_ARG_NAME}_pymod")
+    add_py_mod_src(MOD "${_ARG_NAME}_pymod")
   endif()
 endmacro()
 
@@ -664,7 +619,8 @@ macro(promod3_unittest)
     set(CPP_TESTS)
     set(PY_TESTS)
     if (NOT _ARG_MODULE)
-      message(FATAL_ERROR "invalid use of promod3_unittest(): module name missing")
+      message(FATAL_ERROR
+              "invalid use of promod3_unittest(): module name missing")
     endif()
     set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_BINARY_DIR}/tests/${_ARG_MODULE}")
     file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
@@ -685,6 +641,7 @@ macro(promod3_unittest)
         copy_if_different("${CMAKE_CURRENT_SOURCE_DIR}/${tdata_path}"
           "${tdata_full_path}" "${tdata_file}"
           TARGETS "test_data_${_ARG_MODULE}")
+        add_unit_test_data_target(DAT "test_data_${_ARG_MODULE}")
       endforeach()
     endif(_ARG_DATA)
     foreach(src ${_SOURCES})
@@ -702,20 +659,28 @@ macro(promod3_unittest)
       else()
         add_executable(${_test_name} EXCLUDE_FROM_ALL ${_SOURCES})
       endif()
-      set_target_properties(${_test_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
-      set_target_properties(${_test_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR})
-      set_target_properties(${_test_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR})
+      set_target_properties(${_test_name} PROPERTIES
+                           RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+      set_target_properties(${_test_name} PROPERTIES
+                     RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR})
+      set_target_properties(${_test_name} PROPERTIES
+                   RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR})
       add_dependencies(${_test_name} "test_data_${_ARG_MODULE}")
       target_link_libraries(${_test_name} ${BOOST_UNIT_TEST_LIBRARIES}
                           "${_ARG_PREFIX}_${_ARG_MODULE}")
       add_custom_target("${_test_name}_run"
-                      COMMAND PROMOD3_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} || echo
+                      COMMAND
+     PROMOD3_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} || echo
                       WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                       COMMENT "running checks for module ${_ARG_MODULE}"
                       DEPENDS ${_test_name})
       add_dependencies("${_test_name}_run" "_${_ARG_MODULE}")
+      set(_xml_test_cmd "PROMOD3_ROOT=${STAGE_DIR}")
+      set(_xml_test_cmd ${_xml_test_cmd} ${CMAKE_CURRENT_BINARY_DIR})
+      set(_xml_test_cmd "${_xml_test_cmd}/${_test_name}")
+      set(_xml_test_cmd ${_xml_test_cmd} "--log_format=xml" "--log_level=all")
       add_custom_target("${_test_name}_run_xml"
-                      COMMAND PROMOD3_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} --log_format=xml --log_level=all > ${_test_name}_log.xml || echo
+                      COMMAND ${_xml_test_cmd} > ${_test_name}_log.xml || echo
                       WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                       COMMENT "running checks for module ${_ARG_MODULE}"
                       DEPENDS "_${_ARG_MODULE}" ${_test_name})
@@ -738,16 +703,19 @@ macro(promod3_unittest)
         set(python_path "${python_path}:")
       endif(python_path)
       # we just add OST manually here until we find a more flexible way
-      set(python_path "${python_path}${LIB_STAGE_PATH}/python${PYTHON_VERSION}/site-packages:${OST_ROOT}/${LIB_DIR}/python${PYTHON_VERSION}/site-packages")
+      set(python_path
+       "${python_path}${LIB_STAGE_PATH}/python${PYTHON_VERSION}/site-packages:")
+      set(python_path
+   "${python_path}${OST_ROOT}/${LIB_DIR}/python${PYTHON_VERSION}/site-packages")
       set (PY_TESTS_CMD "PYTHONPATH=${python_path}  ${PYTHON_BINARY}")
       add_custom_target("${py_test}_run"
-                sh -c "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} || echo"
+          sh -c "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} || echo"
                 WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                 COMMENT "running checks ${py_test}" VERBATIM)
       add_dependencies("${py_test}_run" "test_data_${_ARG_MODULE}")
       add_dependencies("${py_test}_run" "_${_ARG_MODULE}")
       add_custom_target("${py_test}_run_xml"
-                sh -c "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} xml || echo"
+      sh -c "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} xml || echo"
                 WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                 COMMENT "running checks ${py_test}" VERBATIM)
       add_dependencies("${py_test}_run_xml" "test_data_${_ARG_MODULE}")
@@ -757,6 +725,37 @@ macro(promod3_unittest)
     endforeach()
 endmacro()
 
+#-------------------------------------------------------------------------------
+# Synopsis:
+#   add_unit_test_data_target(DAT target)
+#
+# Description:
+#   Add a data target for a unit test to PM3_UNIT_TEST_DATA.
+#   DAT - target
+#-------------------------------------------------------------------------------
+macro(add_unit_test_data_target)
+  parse_argument_list(_ARG "DAT" "" ${ARGN})
+  if (NOT _ARG_DAT)
+    message(FATAL_ERROR
+            "invalid use of add_unit_test_data_target(): target missing")
+  endif()
+  if(DEFINED PM3_UNIT_TEST_DATA)
+    set(_DATATARGETS "${PM3_UNIT_TEST_DATA}")
+    set(_NME_FOUND)
+    foreach(nme ${PM3_UNIT_TEST_DATA})
+      if(${nme} STREQUAL ${_ARG_DAT})
+        set(_NME_FOUND TRUE)
+      endif()
+    endforeach()
+    if(NOT _NME_FOUND)
+      list(APPEND _DATATARGETS "${_ARG_DAT}")
+    endif()
+  else()
+    set(_DATATARGETS "${_ARG_DAT}")
+  endif()
+  set(PM3_UNIT_TEST_DATA "${_DATATARGETS}" CACHE INTERNAL "" FORCE)
+endmacro()
+
 #-------------------------------------------------------------------------------
 # make sure the previously detected Python interpreter has the given module
 #-------------------------------------------------------------------------------
@@ -767,7 +766,8 @@ macro(promod3_find_python_module MODULE)
                     OUTPUT_QUIET ERROR_QUIET
                     RESULT_VARIABLE _IMPORT_ERROR)
     if (_IMPORT_ERROR)
-      message(FATAL_ERROR "Could not find python module ${MODULE}. Please install it")
+      message(FATAL_ERROR
+              "Could not find python module ${MODULE}. Please install it")
     else()
       message(STATUS "Found python module ${MODULE}")
       set("PYTHON_MODULE_${MODULE}" FOUND CACHE STRING "" FORCE)
@@ -798,7 +798,10 @@ macro(promod3_match_boost_python_version)
     list(GET _BOOST_PYTHON_LIBRARY ${_LIB_INDEX} _BP_LIB_PATH)
     set(_BOOST_PYTHON_LIBRARY ${_BP_LIB_PATH})
   endif()
-  set(CMAKE_REQUIRED_FLAGS "-I${PYTHON_INCLUDE_PATH} -I${Boost_INCLUDE_DIR} ${PYTHON_LIBRARIES} ${_BOOST_PYTHON_LIBRARY}")
+  set(CMAKE_REQUIRED_FLAGS "-I${PYTHON_INCLUDE_PATH}")
+  set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -I${Boost_INCLUDE_DIR}")
+  set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${PYTHON_LIBRARIES}")
+  set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${_BOOST_PYTHON_LIBRARY}")
   check_cxx_source_runs(
 "#include <boost/python.hpp>
 
@@ -937,10 +940,12 @@ endmacro()
 macro(add_doc_dependency)
   parse_argument_list(_ADD_ARG "NAME;DEP" "" ${ARGN})
   if (NOT _ADD_ARG_NAME)
-    message(FATAL_ERROR "invalid use of add_doc_dependency(): module name missing")
+    message(FATAL_ERROR
+            "invalid use of add_doc_dependency(): module name missing")
   endif()
   if (NOT _ADD_ARG_DEP)
-    message(FATAL_ERROR "invalid use of add_doc_dependency(): dependencies missing")
+    message(FATAL_ERROR
+            "invalid use of add_doc_dependency(): dependencies missing")
   endif()
   if(DEFINED PM3_DOC_DEPS_${_ADD_ARG_NAME})
     set(_DOC_DEPS "${PM3_DOC_DEPS_${_ADD_ARG_NAME}}")
@@ -983,26 +988,57 @@ macro(add_doc_source)
     list(APPEND _DOC_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${rst}")
   endforeach()
   set(PM3_RST_${_ARG_NAME} "${_DOC_SOURCES}" CACHE INTERNAL "" FORCE)
-  add_module_name(MOD ${_ARG_NAME})
+  add_py_mod_src(MOD ${_ARG_NAME})
+endmacro()
+
+#-------------------------------------------------------------------------------
+# Synopsis:
+#   add_py_mod_src(MOD module)
+#
+# Description:
+#   Add a module name to PM3_PY_MS. This is also used to fetch dependencies
+#   on Python code.
+#   MOD - identifier
+#-------------------------------------------------------------------------------
+macro(add_py_mod_src)
+  parse_argument_list(_ARG_DOC "MOD" "" ${ARGN})
+  if (NOT _ARG_DOC_MOD)
+    message(FATAL_ERROR "invalid use of add_py_mod_src(): sources missing")
+  endif()
+  if(DEFINED PM3_PY_MS)
+    set(_MODULES "${PM3_PY_MS}")
+    set(_NME_FOUND)
+    foreach(nme ${PM3_PY_MS})
+      if(${nme} STREQUAL ${_ARG_DOC_MOD})
+        set(_NME_FOUND TRUE)
+      endif()
+    endforeach()
+    if(NOT _NME_FOUND)
+      list(APPEND _MODULES "${_ARG_DOC_MOD}")
+    endif()
+  else()
+    set(_MODULES "${_ARG_DOC_MOD}")
+  endif()
+  set(PM3_PY_MS "${_MODULES}" CACHE INTERNAL "" FORCE)
 endmacro()
 
 #-------------------------------------------------------------------------------
 # Synopsis:
-#   add_module_name(MOD module)
+#   add_to_pymod_list(MOD module)
 #
 # Description:
-#   Add a module name to PM3_MODULES.
+#   Add a module name to PM3_PYMODULES.
 #   MOD - identifier
 #-------------------------------------------------------------------------------
-macro(add_module_name)
+macro(add_to_pymod_list)
   parse_argument_list(_ARG_DOC "MOD" "" ${ARGN})
   if (NOT _ARG_DOC_MOD)
-    message(FATAL_ERROR "invalid use of add_module_name(): sources missing")
+    message(FATAL_ERROR "invalid use of add_to_pymod_list(): module missing")
   endif()
-  if(DEFINED PM3_MODULES)
-    set(_MODULES "${PM3_MODULES}")
+  if(DEFINED PM3_PYMODULES)
+    set(_MODULES "${PM3_PYMODULES}")
     set(_NME_FOUND)
-    foreach(nme ${PM3_MODULES})
+    foreach(nme ${PM3_PYMODULES})
       if(${nme} STREQUAL ${_ARG_DOC_MOD})
         set(_NME_FOUND TRUE)
       endif()
@@ -1013,7 +1049,7 @@ macro(add_module_name)
   else()
     set(_MODULES "${_ARG_DOC_MOD}")
   endif()
-  set(PM3_MODULES "${_MODULES}" CACHE INTERNAL "" FORCE)
+  set(PM3_PYMODULES "${_MODULES}" CACHE INTERNAL "" FORCE)
 endmacro()
 
 #-------------------------------------------------------------------------------
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index ca8a6bab..1b6e7987 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -31,7 +31,10 @@ set(_SPHINX_CONF_SUBST_DICT PROMOD3_VERSION_MAJOR="${PROMOD3_VERSION_MAJOR}"
                             OST_ROOT="${OST_ROOT}"
                             OST_DOC_URL="${OST_DOC_URL}"
                             LIB_DIR="${LIB_DIR}")
-set(_CONF_SUBST_DICT -DINPUT_FILE=${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in -DOUT_FILE=${_SPHINX_CONF_PY})
+
+set(_CONF_SUBST_DICT -DINPUT_FILE=${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in)
+list(APPEND _CONF_SUBST_DICT -DOUT_FILE=${_SPHINX_CONF_PY})
+
 foreach(_subst ${_SPHINX_CONF_SUBST_DICT})
   list(APPEND _CONF_SUBST_DICT -D${_subst})
 endforeach()
@@ -45,7 +48,8 @@ add_custom_command(OUTPUT ${_SPHINX_CONF_PY}
 foreach(_rst_file ${_DOC_RST_FILES})
   add_custom_command(OUTPUT "${_RST_SOURCE_DIR}/${_rst_file}"
                      MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/${_rst_file}"
-                     COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/${_rst_file}" "${_RST_SOURCE_DIR}/${_rst_file}")
+                     COMMAND ${CMAKE_COMMAND} -E copy
+   "${CMAKE_CURRENT_SOURCE_DIR}/${_rst_file}" "${_RST_SOURCE_DIR}/${_rst_file}")
   set(_RST_DEPS ${_RST_DEPS} "${_RST_SOURCE_DIR}/${_rst_file}")
 endforeach()
 # care for a changelog file, if given
@@ -53,12 +57,13 @@ if(DEFINED PM3_DOC_CHANGELOG)
   # copy to different file name
   add_custom_command(OUTPUT "${_RST_SOURCE_DIR}/changelog.rst"
                      MAIN_DEPENDENCY "${PM3_DOC_CHANGELOG}"
-                     COMMAND ${CMAKE_COMMAND} -E copy "${PM3_DOC_CHANGELOG}" "${_RST_SOURCE_DIR}/changelog.rst")
+                     COMMAND ${CMAKE_COMMAND} -E copy
+                      "${PM3_DOC_CHANGELOG}" "${_RST_SOURCE_DIR}/changelog.rst")
   set(_RST_DEPS ${_RST_DEPS} "${_RST_SOURCE_DIR}/changelog.rst")
 endif()
 
 # iterate list of ALL modules registered by pymod()/ add_doc_source()
-foreach(mod ${PM3_MODULES})
+foreach(mod ${PM3_PY_MS})
   # only modules with dedicated rst files are considered for documentation, so
   # we check if a list PM3_RST_{module name} exists (filled by add_doc_source()
   # the following sets up copying for *.rst files only
@@ -98,7 +103,8 @@ set(_SPHINX_INDEX_HTML "${_SPHINX_HTML_DIR}/index.html")
 add_custom_command(OUTPUT ${_SPHINX_INDEX_HTML}
                    MAIN_DEPENDENCY "${_SPHINX_CONF_PY}"
                    DEPENDS ${_RST_DEPS} ${_DOC_MODULE_DEPS}
-                   COMMAND ${SPHINX_BINARY} -b html -c "${_RST_SOURCE_DIR}" "${_RST_SOURCE_DIR}" "${_SPHINX_HTML_DIR}")
+                   COMMAND ${SPHINX_BINARY} -b html -c "${_RST_SOURCE_DIR}"
+                                     "${_RST_SOURCE_DIR}" "${_SPHINX_HTML_DIR}")
 add_custom_target(html DEPENDS ${_SPHINX_INDEX_HTML})
 
 # man target
@@ -108,7 +114,8 @@ set(_SPHINX_MAN "${_SPHINX_MAN_DIR}/promod3.1")
 add_custom_command(OUTPUT ${_SPHINX_MAN}
                    MAIN_DEPENDENCY "${_SPHINX_CONF_PY}"
                    DEPENDS ${_RST_DEPS} ${_DOC_MODULE_DEPS}
-                   COMMAND ${SPHINX_BINARY} -b man -c "${_RST_SOURCE_DIR}" "${_RST_SOURCE_DIR}" "${_SPHINX_MAN_DIR}")
+                   COMMAND ${SPHINX_BINARY} -b man -c "${_RST_SOURCE_DIR}"
+                                      "${_RST_SOURCE_DIR}" "${_SPHINX_MAN_DIR}")
 add_custom_target(man DEPENDS ${_SPHINX_MAN})
 
 # doc target, registered with all
@@ -120,14 +127,17 @@ add_dependencies(doc man)
 set(_SPHINX_DOCTEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/doctest")
 file(MAKE_DIRECTORY ${_SPHINX_DOCTEST_DIR})
 add_custom_target(doctest
-                  COMMAND ${SPHINX_BINARY} -b doctest -c "${_RST_SOURCE_DIR}" "${_RST_SOURCE_DIR}" "${_SPHINX_DOCTEST_DIR}"
-                  DEPENDS "${_SPHINX_CONF_PY}" ${_RST_DEPS} ${_DOC_MODULE_DEPS})
+                  COMMAND ${SPHINX_BINARY} -b doctest -c "${_RST_SOURCE_DIR}"
+                                   "${_RST_SOURCE_DIR}" "${_SPHINX_DOCTEST_DIR}"
+                  DEPENDS "${_SPHINX_CONF_PY}" ${_RST_DEPS} ${_DOC_MODULE_DEPS}
+                                         ${PM3_PYMODULES} ${PM3_UNIT_TEST_DATA})
 
 # linkcheck target
 set(_SPHINX_LINKCHECK_DIR "${CMAKE_CURRENT_BINARY_DIR}/linkcheck")
 file(MAKE_DIRECTORY ${_SPHINX_LINKCHECK_DIR})
 add_custom_target(linkcheck
-                  COMMAND ${SPHINX_BINARY} -b linkcheck -c "${_RST_SOURCE_DIR}" "${_RST_SOURCE_DIR}" "${_SPHINX_LINKCHECK_DIR}"
+                  COMMAND ${SPHINX_BINARY} -b linkcheck -c "${_RST_SOURCE_DIR}"
+                                 "${_RST_SOURCE_DIR}" "${_SPHINX_LINKCHECK_DIR}"
                   DEPENDS "${_SPHINX_CONF_PY}" ${_RST_DEPS} ${_DOC_MODULE_DEPS})
 
 # register doctest & linkcheck with check
@@ -147,6 +157,3 @@ endif()
 install(DIRECTORY ${_SPHINX_HTML_DIR} DESTINATION "share/promod3")
 # install man pages
 install(DIRECTORY ${_SPHINX_MAN_DIR} DESTINATION "share/promod3")
-
-# doctest & linkcheck goes into check, once its created, depend on rst
-# what about extratcting stuff from code? -> autofunction
diff --git a/extras/pre-commit b/extras/pre-commit
index 9512f98e..104a4e53 100755
--- a/extras/pre-commit
+++ b/extras/pre-commit
@@ -211,7 +211,7 @@ def CheckPythonCode(filepath):
   import_re = re.compile('import\s+\*')
   lno = 1
   for line in fh:
-    line = line.strip()
+    line = line.rstrip(os.linesep)
     TestLineWidthExit(line, lno, filepath)
     m_line = re.match('([^#]*)', line)
     ex_line = m_line.group(1)
@@ -228,7 +228,7 @@ def CheckRest(filepath):
   fh = open(filepath, "U")
   lno = 1
   for line in fh:
-    line = line.strip()
+    line = line.rstrip(os.linesep)
     TestLineWidthExit(line, lno, filepath)
     lno += 1
 
@@ -236,7 +236,7 @@ def CheckCmake(filepath):
   fh = open(filepath, "U")
   lno = 1
   for line in fh:
-    line = line.strip()
+    line = line.rstrip(os.linesep)
     TestLineWidthExit(line, lno, filepath)
     lno += 1
 
@@ -244,7 +244,7 @@ def CheckShellScript(filepath):
   fh = open(filepath, "U")
   lno = 1
   for line in fh:
-    line = line.strip()
+    line = line.rstrip(os.linesep)
     TestLineWidthExit(line, lno, filepath)
     lno += 1
 
@@ -252,7 +252,7 @@ def CheckCCode(filepath):
   fh = open(filepath, "U")
   lno = 1
   for line in fh:
-    line = line.strip()
+    line = line.rstrip(os.linesep)
     TestLineWidthExit(line, lno, filepath)
     lno += 1
 ### FUNCTIONS - END
diff --git a/meld/doc/CMakeLists.txt b/meld/doc/CMakeLists.txt
index 9e117822..67ee54a5 100644
--- a/meld/doc/CMakeLists.txt
+++ b/meld/doc/CMakeLists.txt
@@ -1,6 +1,5 @@
 set(MELD_RST
 index.rst
-rawmodel.rst
 )
 
 add_doc_source(NAME meld RST ${MELD_RST})
diff --git a/meld/doc/index.rst b/meld/doc/index.rst
index 88c078f8..b90b30a2 100644
--- a/meld/doc/index.rst
+++ b/meld/doc/index.rst
@@ -2,12 +2,98 @@
 ================================================================================
 
 .. module:: promod3.meld
-  :synopsis: Coordinate modeling and sampling
+  :synopsis: Raw Coordinate Model
+
+.. currentmodule:: promod3.meld
+
+Functionality to build raw (pseudo) models based on a sequence alignment.
+Here is an example of how to build a model from an alignment and a structure.
+
+.. testcode:: meld
+  :hide:
+
+  import os
+  import tempfile
+  from ost import io
+  from promod3 import meld
+
+  aln = io.LoadAlignment('../tests/meld/data/raw-modeling/seq.fasta')
+  template_structure = io.LoadPDB('../tests/meld/data/raw-modeling/gly.pdb',
+                                  restrict_chains='A')
+  aln.AttachView(1, template_structure.Select('peptide=true'))
+  result = meld.BuildRawModel(aln)
+  (fh, fn) = tempfile.mkstemp(suffix='.pdb')
+  io.SavePDB(result.model, fn)
+  os.remove(fn)
+
+.. doctest:: meld
+
+  from ost import io
+  from promod3 import meld
+
+  aln = io.LoadAlignment('seq.fasta')
+  template_structure = io.LoadPDB('gly.pdb', restrict_chains='A')
+  aln.AttachView(1, template_structure.Select('peptide=true'))
+  result = meld.BuildRawModel(aln)
+  io.SavePDB(result.model, 'model.pdb')
+
+
+Raw Coordinate Modeling API
+--------------------------------------------------------------------------------
+
+.. function:: BuildRawModel(alignment, calpha_only=False)
+              BuildRawModel(alignments, calpha_only=False)
+
+  Builds a raw (pseudo) model from the alignment. Can either take a single
+  alignment handle or an alignment handle list. Every list item is treated as a
+  single chain in the final raw model.
+
+  This is a basic protein core modeling algorithm that copies backbone
+  coordinates based on the sequence alignment. For matching residues, the
+  side chain coordinates are also copied. Gaps are ignored. Hydrogen an
+  deuterium atoms are not copied into the model.
+
+  The function tries to reuse as much as possible from the template. Modified
+  residues are treated as follows:
+
+    - Selenium methionine residues are converted to methionine
+
+    - Side chains which contain all atoms of the parent amino acid, e.g.
+      phosphoserine are copied as a whole with the modifications stripped off.
+
+  Residue numbers are set such that missing residue in gaps are honoured and
+  subsequent loop modeling can insert new residues without having to
+  renumber.
   
-This module contains functions and classes to build raw-models for protein
-structures from templates.
+  The returned :class:`RawModelingResult` stores the obtained raw model as well
+  as information about insertions and deletions in the gaps list.
+
+  :param calpha_only: If true, only Calpha atoms will be copied. Side chains
+                      and other backbone atoms are completely ignored.
+  :raises: A :exc:`RuntimeError` when the second sequence does not have an
+     attached structure
+
+.. class:: RawModelingResult
+
+  Holds the result of raw model building. Incredibly minimalistic for now. Will
+  most likely grow a few more members over time to, e.g. to store a detailed
+  report.
+
+  .. attribute:: model
+
+    The resulting model.
+
+    :type: :class:`~ost.mol.EntityHandle`
+
+  .. attribute:: gaps
+
+    List of gaps in the model that could not be copied from the template. These
+    gaps may be the result of insertions/deletions in the alignment or due to
+    missing or incomplete backbone coordinates in the template structure.
+
+
+    :type: :class:`StructuralGapList`
 
-.. toctree:: 
-  :maxdepth: 2
 
-  rawmodel
+..  LocalWords:  currentmodule promod aln AttachView BuildRawModel pdb calpha
+..  LocalWords:  RawModelingResult StructuralGapList
diff --git a/meld/doc/rawmodel.rst b/meld/doc/rawmodel.rst
deleted file mode 100644
index 312c6856..00000000
--- a/meld/doc/rawmodel.rst
+++ /dev/null
@@ -1,80 +0,0 @@
-Raw Coordinate Modeling
-================================================================================
-
-.. currentmodule:: sm.meld
-
-Introduction
---------------------------------------------------------------------------------
-
-Contains function to build raw (pseudo) models based on a sequence alignment. Here is an example of how to build a model from an alignment and a structure.
-
-.. code-block:: python
-  
-  from promod3 import meld
-  
-  aln=io.LoadAlignment('parwise.fasta')
-  template_structure=io.LoadPDB('1ake.pdb', restrict_chains='A')
-  aln.AttachView(1, template_structure.Select('peptide=true'))
-  result=meld.BuildRawModel(aln)
-  io.SavePDB(result.model, 'model.pdb')
-  print 'remaining gaps:'
-  for gap in result.gaps:
-    print ' * %s' % str(gap)
-
-
-Raw Coordinate Modeling API
---------------------------------------------------------------------------------
-
-.. function:: BuildRawModel(alignment, calpha_only=False)
-              BuildRawModel(alignments, calpha_only=False)
-
-  Builds a raw (pseudo) model from the alignment.
-  Can either take a single alignment handle or an alignment handle list.
-  Every list item is treated as a single chain in the final raw model.
-  
-  This is a basic protein core modeling algorithm that copies backbone 
-  coordinates based on the sequence alignment. For matching residues, the 
-  sidechain coordinates are also copied. Gaps are ignored. Hydrogen an deuterium 
-  atoms are not copied into the model.
-  
-  The function tries to reuse as much as possible from the template. Modified 
-  residues are treated as follows:
-  
-    - Selenium methionine residues are converted to methionines
-    
-    - Sidechains which contain all atoms of the parent amino acid, e.g. 
-      phosphoserine are copied as a whole with the modifications stripped off.
-    
-  Residue numbers are set such that missing residue in gaps are honored and 
-  subsequent loop modeling can insert new residues without having to 
-  renumber.
-  
-  The returned :class:`RawModelingResult` stores the obtained raw model as well 
-  as information about insertions and deletions in the gaps list.
-  
-  :param calpha_only: If true, only Calpha atoms will be copied. Sidechains and 
-     other backbone atoms are completely ignored.
-  :raises: A :exc:`RuntimeError` when the second sequence does not have an 
-     attached structure
-
-.. class:: RawModelingResult
-
-  Holds the result of raw model building. Incredibly minimalistic for now. Will 
-  most likely grow a few more members over time to, e.g. to store a detailed 
-  report.
-  
-  .. attribute:: model
-  
-    The resulting model.
-    
-    :type: :class:`~ost.mol.EntityHandle`
-  
-  .. attribute:: gaps
-    
-    List of gaps in the model that could not be copied from the template. These 
-    gaps may be the result of insertions/deletions in the alignment or due to 
-    missing or incomplete backbone coordinates in the template structure.
-    
-    
-    :type: :class:`StructuralGapList`
-    
-- 
GitLab