nxtomomill 2.2.0.dev0__tar.gz → 2.2.0.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. {nxtomomill-2.2.0.dev0/nxtomomill.egg-info → nxtomomill-2.2.0.dev1}/PKG-INFO +2 -2
  2. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/__main__.py +1 -1
  3. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/h52nx.py +19 -2
  4. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/baseacquisition.py +27 -6
  5. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/standardacquisition.py +16 -13
  6. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/tests/test_acquisition.py +33 -0
  7. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/utils/_context.py +7 -0
  8. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/hdf5converter.py +7 -0
  9. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/tests/test_h52nx_utils.py +14 -0
  10. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/tests/test_hdf5converter.py +165 -0
  11. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/config/confighandler.py +1 -0
  12. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/config/tests/test_confighandler.py +1 -0
  13. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/h52nx/general_section.py +22 -0
  14. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/h52nx/h52nx.py +1 -0
  15. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1/nxtomomill.egg-info}/PKG-INFO +2 -2
  16. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill.egg-info/SOURCES.txt +0 -1
  17. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill.egg-info/requires.txt +1 -1
  18. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/pyproject.toml +2 -2
  19. nxtomomill-2.2.0.dev0/nxtomomill/converter/edf/_Blosc2Jp2kWrapper.py +0 -63
  20. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/LICENSE +0 -0
  21. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/README.md +0 -0
  22. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/doc/conf.py +0 -0
  23. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/__init__.py +0 -0
  24. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/__init__.py +0 -0
  25. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/blissfluo2nx.py +0 -0
  26. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/blissfluoconfig.py +0 -0
  27. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/dxfile2nx.py +0 -0
  28. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/edf2nx.py +0 -0
  29. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/edf2nx_check.py +0 -0
  30. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/edfconfig.py +0 -0
  31. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/fluo2nx.py +0 -0
  32. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/fluoconfig.py +0 -0
  33. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/fscan2nx.py +0 -0
  34. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/h5config.py +0 -0
  35. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/nxcopy.py +0 -0
  36. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/patch_nx.py +0 -0
  37. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/split_nxfile.py +0 -0
  38. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/tests/test_bliss_fluo2nx_app.py +0 -0
  39. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/tests/test_dxfile2nx_app.py +0 -0
  40. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/tests/test_edf2nx_app.py +0 -0
  41. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/tests/test_edf_config_app.py +0 -0
  42. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/tests/test_fluo2nx_app.py +0 -0
  43. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/tests/test_h52nx_app.py +0 -0
  44. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/tests/test_h5_config_app.py +0 -0
  45. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/tests/test_nx_copy.py +0 -0
  46. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/tests/test_patch_nx_app.py +0 -0
  47. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/tests/test_split_nxfile_app.py +0 -0
  48. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/z_concatenate_scans.py +0 -0
  49. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/app/zstages2nxs.py +0 -0
  50. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/__init__.py +0 -0
  51. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/baseconverter.py +0 -0
  52. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/dxfile/__init__.py +0 -0
  53. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/dxfile/dxfileconverter.py +0 -0
  54. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/dxfile/tests/test_dxfile.py +0 -0
  55. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/edf/__init__.py +0 -0
  56. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/edf/checks.py +0 -0
  57. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/edf/edfconverter.py +0 -0
  58. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/edf/tests/test_checks.py +0 -0
  59. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/edf/tests/test_edf2nx.py +0 -0
  60. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/edf/tests/test_edf2nx_check.py +0 -0
  61. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/fluo/__init__.py +0 -0
  62. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/fluo/blissfluoscan.py +0 -0
  63. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/fluo/fluoconverter.py +0 -0
  64. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/fluo/fluoscan.py +0 -0
  65. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/fluo/tests/__init__.py +0 -0
  66. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/fluo/tests/test_fluoscan2D.py +0 -0
  67. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/fluo/tests/test_fluoscan3D.py +0 -0
  68. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/fscan/__init__.py +0 -0
  69. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/fscan/fscanconverter.py +0 -0
  70. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/__init__.py +0 -0
  71. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/__init__.py +0 -0
  72. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/_bliss_activeconfig.py +0 -0
  73. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/backandforth.py +0 -0
  74. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/blisstomoconfig.py +0 -0
  75. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/multitomo.py +0 -0
  76. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/pcotomoacquisition.py +0 -0
  77. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/tests/bliss_tomo_datasets.py +0 -0
  78. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/tests/test_acquisition_utils.py +0 -0
  79. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/tests/test_back_and_forth.py +0 -0
  80. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/tests/test_bliss_tomo_config.py +0 -0
  81. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/tests/test_holotomo.py +0 -0
  82. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/tests/test_legacy.py +0 -0
  83. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/tests/test_multitomo_zseries.py +0 -0
  84. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/tests/test_multitomoacquisition.py +0 -0
  85. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/utils/__init__.py +0 -0
  86. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/utils/_keys.py +0 -0
  87. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/utils/_scan_type_finder.py +0 -0
  88. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/utils/bliss_scan_type.py +0 -0
  89. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/utils/detector.py +0 -0
  90. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/utils/machine_current.py +0 -0
  91. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/utils/series.py +0 -0
  92. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/utils/timestamps.py +0 -0
  93. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisition/zseriesacquisition.py +0 -0
  94. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/acquisitionConstructor.py +0 -0
  95. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/post_processing/__init__.py +0 -0
  96. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/post_processing/dark_flat_copy.py +0 -0
  97. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/tests/test_frame_flip.py +0 -0
  98. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/hdf5/utils.py +0 -0
  99. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/converter/version.py +0 -0
  100. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/__init__.py +0 -0
  101. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/config/__init__.py +0 -0
  102. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/config/configbase.py +0 -0
  103. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/config/dxconfig.py +0 -0
  104. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/config/edfconfig.py +0 -0
  105. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/config/fluoconfig.py +0 -0
  106. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/config/hdf5config.py +0 -0
  107. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/config/tests/__init__.py +0 -0
  108. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/tests/test_frame_group.py +0 -0
  109. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/io/tests/utils.py +0 -0
  110. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/__init__.py +0 -0
  111. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/base/ConfigBase.py +0 -0
  112. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/base/FrmFlatToNestedBase.py +0 -0
  113. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/base/NestedModelBase.py +0 -0
  114. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/base/__init__.py +0 -0
  115. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/base/general_section.py +0 -0
  116. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/base/instrument_section.py +0 -0
  117. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/base/source_section.py +0 -0
  118. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/blissfluo2nx/__init__.py +0 -0
  119. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/blissfluo2nx/blissfluo2nx.py +0 -0
  120. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/blissfluo2nx/general_section.py +0 -0
  121. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/dx2nx.py +0 -0
  122. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/edf2nx/__init__.py +0 -0
  123. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/edf2nx/dark_and_flat_section.py +0 -0
  124. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/edf2nx/detector_section.py +0 -0
  125. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/edf2nx/edf2nx.py +0 -0
  126. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/edf2nx/general_section.py +0 -0
  127. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/edf2nx/keys_section.py +0 -0
  128. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/edf2nx/sample_section.py +0 -0
  129. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/edf2nx/unit_section.py +0 -0
  130. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/fluo2nx/__init__.py +0 -0
  131. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/fluo2nx/fluo2nx.py +0 -0
  132. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/fluo2nx/general_section.py +0 -0
  133. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/h52nx/FrameGroup.py +0 -0
  134. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/h52nx/__init__.py +0 -0
  135. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/h52nx/_acquisitionstep.py +0 -0
  136. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/h52nx/_context.py +0 -0
  137. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/h52nx/entries_and_title_section.py +0 -0
  138. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/h52nx/extra_params_section.py +0 -0
  139. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/h52nx/frame_type_section.py +0 -0
  140. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/h52nx/keys_section.py +0 -0
  141. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/h52nx/multitomo_section.py +0 -0
  142. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/tests/test_context.py +0 -0
  143. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/tests/test_edf2nx_model.py +0 -0
  144. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/tests/test_fluo2nx_model.py +0 -0
  145. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/tests/test_h52nx_model.py +0 -0
  146. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/tests/test_io_utils.py +0 -0
  147. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/models/utils.py +0 -0
  148. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/settings.py +0 -0
  149. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/test.py +0 -0
  150. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/tests/__init__.py +0 -0
  151. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/tests/datasets.py +0 -0
  152. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/tests/resources/__init__.py +0 -0
  153. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/tests/resources/edf2nx_config_files/__init__.py +0 -0
  154. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/tests/resources/fluo2nx_config_files/__init__.py +0 -0
  155. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/tests/resources/h52nx_config_files/__init__.py +0 -0
  156. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/tests/test_version.py +0 -0
  157. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/tests/utils/__init__.py +0 -0
  158. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/tests/utils/bliss.py +0 -0
  159. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/tests/utils/dxfile.py +0 -0
  160. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/__init__.py +0 -0
  161. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/_os.py +0 -0
  162. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/flat_reducer.py +0 -0
  163. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/h5pyutils.py +0 -0
  164. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/hdf5.py +0 -0
  165. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/io.py +0 -0
  166. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/nexus.py +0 -0
  167. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/pintutils.py +0 -0
  168. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/tests/test_flat_reducer.py +0 -0
  169. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/tests/test_h5pyutils.py +0 -0
  170. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/tests/test_nexus_utils.py +0 -0
  171. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/tests/test_utils.py +0 -0
  172. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill/utils/utils.py +0 -0
  173. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill.egg-info/dependency_links.txt +0 -0
  174. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill.egg-info/entry_points.txt +0 -0
  175. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/nxtomomill.egg-info/top_level.txt +0 -0
  176. {nxtomomill-2.2.0.dev0 → nxtomomill-2.2.0.dev1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nxtomomill
3
- Version: 2.2.0.dev0
3
+ Version: 2.2.0.dev1
4
4
  Summary: applications and library to convert raw format to NXtomo format
5
5
  Author-email: Henri Payno <henri.payno@esrf.fr>, Pierre Paleo <pierre.paleo@esrf.fr>, Pierre-Olivier Autran <pierre-olivier.autran@esrf.fr>, Jérôme Lesaint <jerome.lesaint@esrf.fr>, Alessandro Mirone <mirone@esrf.fr>
6
6
  License:
@@ -58,7 +58,7 @@ Requires-Dist: silx>=2.0
58
58
  Requires-Dist: nxtomo>=3.1.0dev1
59
59
  Requires-Dist: pint
60
60
  Requires-Dist: packaging
61
- Requires-Dist: tomoscan[full]>=3.0.0dev0
61
+ Requires-Dist: tomoscan>=3.0.0dev0
62
62
  Requires-Dist: tomobase>=0.0.0dev0
63
63
  Requires-Dist: tqdm
64
64
  Requires-Dist: pydantic
@@ -84,7 +84,7 @@ class Launcher(_Launcher):
84
84
  replacement=deprecation_info.replacement,
85
85
  since_version=deprecation_info.since,
86
86
  )
87
- super().execute(argv=argv)
87
+ return super().execute(argv=argv)
88
88
 
89
89
  def print_help(self):
90
90
  """Print the help to stdout."""
@@ -15,7 +15,7 @@ import logging
15
15
  from tqdm import tqdm
16
16
 
17
17
  from nxtomomill import utils
18
- from nxtomomill.converter import from_h5_to_nx
18
+ from nxtomomill.converter.hdf5.hdf5converter import _H5ToNxConverter
19
19
  from nxtomomill.io.config.confighandler import (
20
20
  SETTABLE_PARAMETERS_UNITS,
21
21
  TomoHDF5ConfigHandler,
@@ -317,6 +317,20 @@ def main(argv):
317
317
  "Sometime relative link cannot be solved (GPFS vs NFS). "
318
318
  "In this case you might be forced to use absolute path.",
319
319
  )
320
+ parser.add_argument(
321
+ "--no-resolve-vds",
322
+ "--no-resolve-vds-links",
323
+ "--no_resolve_vds",
324
+ dest="resolve_vds",
325
+ action="store_false",
326
+ default=None,
327
+ help="Do not resolve external links and virtual datasets (VDS) down to "
328
+ "their final source when building the output NXtomo. Can speed up the "
329
+ "conversion for datasets with many nested links, at the cost of the "
330
+ "output file containing VDS pointing to other VDS instead of direct "
331
+ "links to the raw data. Defaults to the 'NXTOMOMILL_RESOLVE_VDS' "
332
+ "environment variable if set, else resolving is enabled.",
333
+ )
320
334
  options = parser.parse_args(argv[1:])
321
335
  if options.request_input:
322
336
  callback_det_sel = _ask_for_selecting_detector
@@ -335,9 +349,12 @@ def main(argv):
335
349
  configuration_handler.configuration.log_level
336
350
  )
337
351
  with tqdm(desc="h52nx", delay=1, bar_format="{l_bar}{bar}") as progress:
338
- from_h5_to_nx(
352
+ converter = _H5ToNxConverter(
339
353
  configuration=configuration_handler.configuration,
340
354
  progress=progress,
341
355
  input_callback=None,
342
356
  detector_sel_callback=callback_det_sel,
343
357
  )
358
+ converter.convert()
359
+ if converter.has_failed_acquisitions:
360
+ return 1
@@ -31,7 +31,7 @@ from silx.io.utils import h5py_read_dataset
31
31
 
32
32
  from nxtomomill.models.h52nx.h52nx import H52nxModel
33
33
  from .utils._keys import keys_to_str_tuple
34
- from .utils._context import read_key, MissingValue
34
+ from .utils._context import read_key, MissingValue, InvalidValue
35
35
 
36
36
  _ureg = pint.get_application_registry()
37
37
  _logger = logging.getLogger(__name__)
@@ -300,6 +300,7 @@ class BaseAcquisition:
300
300
  file_path=output_file,
301
301
  data_path=data_path,
302
302
  use_abs_path_for_vds=self.configuration.use_abs_path_for_vds,
303
+ overwrite=self.configuration.overwrite,
303
304
  )
304
305
  # check rotation angle
305
306
  if nx_tomo.sample.rotation_angle is not None:
@@ -408,6 +409,11 @@ class BaseAcquisition:
408
409
  except MissingValue:
409
410
  # skip values containing '*DIS*'
410
411
  continue
412
+ except InvalidValue:
413
+ # dataset reports an 'ERR' value: let it propagate, the
414
+ # caller decides how to handle it (e.g. translations
415
+ # fall back to None instead of trying other keys)
416
+ raise
411
417
  except KeyError as e:
412
418
  _logger.info(
413
419
  f"Cannot solve key {key}. Most likely one dataset is not there. Error is {e}"
@@ -697,7 +703,7 @@ class BaseAcquisition:
697
703
  _logger.warning(mess)
698
704
  return ([0] * n_frame) * _ureg.meter
699
705
 
700
- def _get_translation_x(self, root_node, n_frame) -> pint.quantity:
706
+ def _get_translation_x(self, root_node, n_frame) -> pint.Quantity | None:
701
707
  """return the list of translation for each frame"""
702
708
  for grp in self._get_positioners_node(root_node), root_node:
703
709
  try:
@@ -708,6 +714,11 @@ class BaseAcquisition:
708
714
  info_retrieve="x base translation",
709
715
  expected_unit=_ureg.mm,
710
716
  )
717
+ except InvalidValue:
718
+ _logger.error(
719
+ f"translation x reports an 'ERR' value for {root_node.name}. Translation x will be set to None."
720
+ )
721
+ return None
711
722
  except (ValueError, KeyError):
712
723
  pass
713
724
  else:
@@ -721,7 +732,7 @@ class BaseAcquisition:
721
732
  _logger.warning(mess)
722
733
  return ([0] * n_frame) * _ureg.meter
723
734
 
724
- def _get_translation_y(self, root_node, n_frame) -> pint.quantity:
735
+ def _get_translation_y(self, root_node, n_frame) -> pint.Quantity | None:
725
736
  """return the list of translation for each frame"""
726
737
  for grp in self._get_positioners_node(root_node), root_node:
727
738
  try:
@@ -732,6 +743,11 @@ class BaseAcquisition:
732
743
  info_retrieve="y base translation",
733
744
  expected_unit=_ureg.mm,
734
745
  )
746
+ except InvalidValue:
747
+ _logger.error(
748
+ f"translation y reports an 'ERR' value for {root_node.name}. Translation y will be set to None."
749
+ )
750
+ return None
735
751
  except (ValueError, KeyError):
736
752
  pass
737
753
  else:
@@ -748,7 +764,7 @@ class BaseAcquisition:
748
764
  @staticmethod
749
765
  def get_translation_z_frm(
750
766
  root_node, n_frame: int, configuration: H52nxModel
751
- ) -> pint.Quantity:
767
+ ) -> pint.Quantity | None:
752
768
  for grp in BaseAcquisition._get_positioners_node(root_node), root_node:
753
769
  try:
754
770
  z_tr, unit = BaseAcquisition._get_node_values_for_frame_array(
@@ -758,6 +774,11 @@ class BaseAcquisition:
758
774
  info_retrieve="z translation",
759
775
  expected_unit=_ureg.mm,
760
776
  )
777
+ except InvalidValue:
778
+ _logger.error(
779
+ f"translation z reports an 'ERR' value for {root_node.name}. Translation z will be set to None."
780
+ )
781
+ return None
761
782
  except (ValueError, KeyError):
762
783
  pass
763
784
  else:
@@ -771,7 +792,7 @@ class BaseAcquisition:
771
792
  _logger.warning(mess)
772
793
  return ([0] * n_frame) * _ureg.meter
773
794
 
774
- def _get_translation_z(self, root_node, n_frame) -> pint.Quantity:
795
+ def _get_translation_z(self, root_node, n_frame) -> pint.Quantity | None:
775
796
  """return the list of translation z for each frame"""
776
797
  return self.get_translation_z_frm(
777
798
  root_node=root_node,
@@ -804,7 +825,7 @@ class BaseAcquisition:
804
825
  else:
805
826
  mess += "default value will be set. (0)"
806
827
  _logger.warning(mess)
807
- return 0 * _ureg.second
828
+ return numpy.zeros(n_frame) * _ureg.second
808
829
 
809
830
  def get_axis_scale_types(self):
810
831
  """
@@ -346,19 +346,22 @@ class StandardAcquisition(BaseAcquisition):
346
346
  image_key_control = frame_type.to_image_key_control()
347
347
  self._image_key_control.extend([image_key_control.value] * n_frame)
348
348
 
349
- try:
350
- solved_camera_dataset_urls = resolve_link(
351
- dataset_url=camera_dataset_url,
352
- dataset=data_dataset,
353
- dataset_link=data_dataset_link,
354
- open_mode_for_reading=self.configuration.open_mode_for_reading,
355
- )
356
- except OSError as e:
357
- # This can happen if one fine cannot be found. In test for example where we are only using the master file
358
- # and low level bliss / tango .h5 files are not existing
359
- _logger.warning(
360
- "Fail to solve camera dataset links and VDS. Error is %s", e
361
- )
349
+ if self.configuration.resolve_vds:
350
+ try:
351
+ solved_camera_dataset_urls = resolve_link(
352
+ dataset_url=camera_dataset_url,
353
+ dataset=data_dataset,
354
+ dataset_link=data_dataset_link,
355
+ open_mode_for_reading=self.configuration.open_mode_for_reading,
356
+ )
357
+ except OSError as e:
358
+ # This can happen if one fine cannot be found. In test for example where we are only using the master file
359
+ # and low level bliss / tango .h5 files are not existing
360
+ _logger.warning(
361
+ "Fail to solve camera dataset links and VDS. Error is %s", e
362
+ )
363
+ solved_camera_dataset_urls = (camera_dataset_url,)
364
+ else:
362
365
  solved_camera_dataset_urls = (camera_dataset_url,)
363
366
 
364
367
  n_total_frame_solved = 0
@@ -3,6 +3,7 @@
3
3
  import os
4
4
  import tempfile
5
5
 
6
+ import h5py
6
7
  import pytest
7
8
  from silx.io.url import DataUrl
8
9
 
@@ -52,6 +53,38 @@ def test_get_dataset_name_from_motor():
52
53
  get_dataset_name_from_motor(set_3, "rotation")
53
54
 
54
55
 
56
+ @pytest.mark.parametrize("raises_error", (True, False))
57
+ def test_translation_with_err_value(tmp_path, raises_error):
58
+ """
59
+ Test that translation x, y and z are set to None (instead of failing)
60
+ when the corresponding dataset reports an 'ERR' value.
61
+ """
62
+ file_path = os.path.join(tmp_path, "test.h5")
63
+ with HDF5File(file_path, mode="w") as h5f:
64
+ h5f["/entry/instrument/positioners/tx"] = "ERR"
65
+ h5f["/entry/instrument/positioners/ty"] = "ERR"
66
+ h5f["/entry/instrument/positioners/tz"] = "ERR"
67
+
68
+ config = TomoHDF5Config()
69
+ config.raises_error = raises_error
70
+ config.translation_x_keys = ("tx",)
71
+ config.translation_y_keys = ("ty",)
72
+ config.translation_z_keys = ("tz",)
73
+
74
+ url = DataUrl(file_path=file_path, data_path="/entry", scheme="silx")
75
+ std_acq = BaseAcquisition(
76
+ root_url=url,
77
+ configuration=config,
78
+ detector_sel_callback=None,
79
+ start_index=0,
80
+ )
81
+ with h5py.File(file_path, mode="r") as h5f:
82
+ root_node = h5f["/entry"]
83
+ assert std_acq._get_translation_x(root_node=root_node, n_frame=1) is None
84
+ assert std_acq._get_translation_y(root_node=root_node, n_frame=1) is None
85
+ assert std_acq._get_translation_z(root_node=root_node, n_frame=1) is None
86
+
87
+
55
88
  def test_frame_flips(tmp_path, monkeypatch):
56
89
  # make sure the result is obtained by using the "instrument/{active_config_tomo_detector}/data_axes" path.
57
90
  monkeypatch.setattr(
@@ -163,6 +163,10 @@ class MissingValue(ValueError):
163
163
  """Raised if a dataset contains 'DIS' - not saved"""
164
164
 
165
165
 
166
+ class InvalidValue(ValueError):
167
+ """Raised if a dataset contains 'ERR' - value could not be read from the hardware"""
168
+
169
+
166
170
  def read_key(
167
171
  key: str,
168
172
  node: h5py.Group,
@@ -210,6 +214,9 @@ def read_key(
210
214
  # skip values containing '*DIS*'
211
215
  if isinstance(values, str) and values == "*DIS*":
212
216
  raise MissingValue(f"dataset {dataset_name} has not been recorded")
217
+ # dataset reports an 'ERR' value if the hardware failed to record it
218
+ if isinstance(values, str) and values == "ERR":
219
+ raise InvalidValue(f"dataset {dataset_name} reports an 'ERR' value")
213
220
 
214
221
  first_dataset = dataset_names[0]
215
222
  result_unit = dataset_units[first_dataset] or expected_unit
@@ -146,6 +146,7 @@ class _H5ToNxConverter(BaseConverter):
146
146
  self._detector_sel_callback = detector_sel_callback
147
147
  self._acquisitions = []
148
148
  self._entries_created = []
149
+ self._conversion_errors: list[tuple[str, Exception]] = []
149
150
  self._z_series_v2_v3: list[list[ZSeriesBaseAcquisition]] = []
150
151
  # bliss z-series for version 2 and 3. Can be used for post-processing
151
152
  self.preprocess()
@@ -176,6 +177,11 @@ class _H5ToNxConverter(BaseConverter):
176
177
  def acquisitions(self):
177
178
  return self._acquisitions
178
179
 
180
+ @property
181
+ def has_failed_acquisitions(self) -> bool:
182
+ """True if at least one acquisition failed to be converted (and the error was not raised, see 'raises_error')"""
183
+ return len(self._conversion_errors) > 0
184
+
179
185
  def preprocess(self):
180
186
  self._preprocess_urls()
181
187
  self._check_conversion_is_possible()
@@ -311,6 +317,7 @@ class _H5ToNxConverter(BaseConverter):
311
317
  exc_info=e,
312
318
  )
313
319
  acquisition_to_nxtomo[acquisition] = None
320
+ self._conversion_errors.append((root_location, e))
314
321
  else:
315
322
  res.extend(new_entries)
316
323
  acquisition_to_nxtomo[acquisition] = new_entries
@@ -18,6 +18,7 @@ from nxtomomill.converter.hdf5.acquisition.utils._context import (
18
18
  update_config_keys_from_tomo_config_context,
19
19
  read_key,
20
20
  MissingValue,
21
+ InvalidValue,
21
22
  )
22
23
  from nxtomomill.converter.hdf5.acquisition.blisstomoconfig import TomoConfig
23
24
  from nxtomomill.converter.hdf5.acquisition.utils._keys import _Key
@@ -151,6 +152,10 @@ def read_key_datasets(tmp_path):
151
152
  f.create_dataset("missing_data/dataset9", data="*DIS*")
152
153
  f.create_dataset("missing_data/dataset10", data=numpy.random.random(10))
153
154
 
155
+ # Create datasets with 'ERR' (hardware failed to record the value)
156
+ f.create_dataset("invalid_data/dataset22", data="ERR")
157
+ f.create_dataset("invalid_data/dataset23", data=numpy.random.random(10))
158
+
154
159
  # Create datasets with coherent units (but different)
155
160
  f.create_dataset("with_coherent_units/dataset11", data=numpy.ones(10))
156
161
  f["with_coherent_units/dataset11"].attrs["unit"] = "meter"
@@ -214,6 +219,15 @@ def test_read_key(read_key_datasets, caplog):
214
219
  expected_unit=_ureg.meter,
215
220
  )
216
221
 
222
+ # test with dataset reporting an 'ERR' value
223
+ with pytest.raises(InvalidValue):
224
+ read_key(
225
+ key="dataset22+dataset23",
226
+ node=h5f["invalid_data"],
227
+ info_retrieve="",
228
+ expected_unit=_ureg.meter,
229
+ )
230
+
217
231
  # test with dataset with coherent size and no unit
218
232
  quantity: pint.Quantity = read_key(
219
233
  key="dataset7+dataset8",
@@ -1415,6 +1415,171 @@ def test_id16a_use_case(tmp_path):
1415
1415
  transformation.transformation_values.magnitude == numpy.array([0.0])
1416
1416
 
1417
1417
 
1418
+ def test_resolve_vds_option(tmp_path, monkeypatch):
1419
+ """
1420
+ Test that the 'resolve_vds' configuration option correctly enables /
1421
+ disables the resolving of external links and virtual datasets (VDS)
1422
+ when building the camera dataset of the output NXtomo.
1423
+ """
1424
+ import nxtomomill.converter.hdf5.acquisition.standardacquisition as standardacquisition_module
1425
+
1426
+ folder = tmp_path / "output_test_resolve_vds_option"
1427
+ folder.mkdir()
1428
+ bliss_mock = MockBlissAcquisition(
1429
+ n_sample=1,
1430
+ n_sequence=1,
1431
+ n_scan_per_sequence=2,
1432
+ n_darks=1,
1433
+ n_flats=1,
1434
+ with_nx_detector_attr=True,
1435
+ output_dir=folder,
1436
+ detector_name="pcolinux",
1437
+ create_tomo_config=False,
1438
+ )
1439
+ sample = bliss_mock.samples[0]
1440
+
1441
+ call_counter = {"n": 0}
1442
+ original_resolve_link = standardacquisition_module.resolve_link
1443
+
1444
+ def _counting_resolve_link(*args, **kwargs):
1445
+ call_counter["n"] += 1
1446
+ return original_resolve_link(*args, **kwargs)
1447
+
1448
+ monkeypatch.setattr(
1449
+ standardacquisition_module, "resolve_link", _counting_resolve_link
1450
+ )
1451
+
1452
+ config = TomoHDF5Config()
1453
+ config.input_file = sample.sample_file
1454
+ config.single_file = True
1455
+ config.sample_x_keys = ("sx",)
1456
+ config.sample_y_keys = ("sy",)
1457
+ config.translation_x_keys = ("tx",)
1458
+
1459
+ # by default (and with 'resolve_vds' explicitly set to True) links / VDS are resolved
1460
+ config.resolve_vds = True
1461
+ config.output_file = str(tmp_path / "output_resolve_vds_true.nx")
1462
+ converter.from_h5_to_nx(configuration=config)
1463
+ assert call_counter["n"] > 0
1464
+ assert os.path.exists(config.output_file)
1465
+
1466
+ # disabling 'resolve_vds' must skip the resolving step entirely
1467
+ call_counter["n"] = 0
1468
+ config.resolve_vds = False
1469
+ config.output_file = str(tmp_path / "output_resolve_vds_false.nx")
1470
+ converter.from_h5_to_nx(configuration=config)
1471
+ assert call_counter["n"] == 0
1472
+ assert os.path.exists(config.output_file)
1473
+
1474
+
1475
+ def test_single_file_and_overwrite_from_cli(tmp_path):
1476
+ """
1477
+ Test that the `--single-file` and `--overwrite` options provided from
1478
+ the CLI are correctly propagated down to the NXtomo saving step.
1479
+ """
1480
+ folder = tmp_path / "output_test_single_file_and_overwrite_from_cli"
1481
+ folder.mkdir()
1482
+ bliss_mock = MockBlissAcquisition(
1483
+ n_sample=1,
1484
+ n_sequence=1,
1485
+ n_scan_per_sequence=2,
1486
+ n_darks=1,
1487
+ n_flats=1,
1488
+ with_nx_detector_attr=True,
1489
+ output_dir=folder,
1490
+ detector_name="pcolinux",
1491
+ create_tomo_config=False,
1492
+ )
1493
+ sample = bliss_mock.samples[0]
1494
+ output_file = sample.sample_file.replace(".h5", ".nx")
1495
+
1496
+ config = H52nxModel()
1497
+ config.input_file = sample.sample_file
1498
+ config.output_file = output_file
1499
+ config.single_file = True
1500
+ config.request_input = False
1501
+ config.raises_error = True
1502
+ config.overwrite = False
1503
+ config.sample_x_keys = ("sx",)
1504
+ config.sample_y_keys = ("sy",)
1505
+ config.translation_x_keys = ("tx",)
1506
+
1507
+ config_file = tmp_path / "config.cfg"
1508
+ config.to_cfg_file(file_path=str(config_file))
1509
+
1510
+ cmd = (
1511
+ sys.executable,
1512
+ "-m",
1513
+ "nxtomomill",
1514
+ "h52nx",
1515
+ sample.sample_file,
1516
+ output_file,
1517
+ "--config",
1518
+ config_file,
1519
+ )
1520
+
1521
+ # first call creates the output file
1522
+ assert subprocess.call(cmd, cwd=tmp_path) == 0 # nosec B603
1523
+ assert os.path.exists(output_file)
1524
+
1525
+ # calling it again without `--overwrite` must fail as the output file already exists
1526
+ # and 'overwrite' is set to False in the configuration
1527
+ assert subprocess.call(cmd, cwd=tmp_path) != 0 # nosec B603
1528
+
1529
+ # calling it again with `--overwrite` provided from the CLI must succeed: the option must be
1530
+ # forwarded to the NXtomo saving step even in `--single-file` mode
1531
+ assert subprocess.call((*cmd, "--overwrite"), cwd=tmp_path) == 0 # nosec B603
1532
+
1533
+
1534
+ def test_cli_exit_code_on_failed_entry(tmp_path):
1535
+ """
1536
+ Test that the CLI exits with a non-zero status code when an entry fails
1537
+ to be converted, even though 'raises_error' is left to its default value
1538
+ (False), in which case the error is logged and the conversion carries on
1539
+ with the other entries instead of raising.
1540
+ """
1541
+ folder = tmp_path / "output_test_cli_exit_code_on_failed_entry"
1542
+ folder.mkdir()
1543
+ bliss_mock = MockBlissAcquisition(
1544
+ n_sample=1,
1545
+ n_sequence=1,
1546
+ n_scan_per_sequence=2,
1547
+ n_darks=1,
1548
+ n_flats=1,
1549
+ with_nx_detector_attr=True,
1550
+ output_dir=folder,
1551
+ detector_name="pcolinux",
1552
+ create_tomo_config=False,
1553
+ )
1554
+ sample = bliss_mock.samples[0]
1555
+ output_file = sample.sample_file.replace(".h5", ".nx")
1556
+
1557
+ cmd = (
1558
+ sys.executable,
1559
+ "-m",
1560
+ "nxtomomill",
1561
+ "h52nx",
1562
+ sample.sample_file,
1563
+ output_file,
1564
+ "--single-file",
1565
+ "--no-input",
1566
+ "--sample_x_keys",
1567
+ "sx",
1568
+ "--sample_y_keys",
1569
+ "sy",
1570
+ )
1571
+
1572
+ # first call creates the output file and must succeed
1573
+ assert subprocess.call(cmd, cwd=tmp_path) == 0 # nosec B603
1574
+ assert os.path.exists(output_file)
1575
+
1576
+ # calling it again (without `--overwrite` nor `--raises-error`) makes the
1577
+ # entry conversion fail internally (it is logged and the conversion is
1578
+ # not interrupted), the CLI must still report the failure through its
1579
+ # exit code
1580
+ assert subprocess.call(cmd, cwd=tmp_path) != 0 # nosec B603
1581
+
1582
+
1418
1583
  def test_warning(tmp_path, caplog):
1419
1584
  """Test that the application raises a warning if bliss acquisition has 'end_reason' different than 'SUCCESS'"""
1420
1585
  config = TomoHDF5Config()
@@ -153,6 +153,7 @@ class TomoHDF5ConfigHandler:
153
153
  "alignment_titles",
154
154
  "open_mode_for_reading",
155
155
  "output_entries",
156
+ "resolve_vds",
156
157
  ):
157
158
  opt_value = getattr(options, opt_name)
158
159
  if opt_value is not None:
@@ -46,6 +46,7 @@ class _ARParseMock(object):
46
46
  self.use_abs_path_for_vds = None
47
47
  self.open_mode_for_reading = "robust"
48
48
  self.output_entries = None
49
+ self.resolve_vds = None
49
50
 
50
51
 
51
52
  def test_creation_from_config_file(tmp_path):
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import os
3
4
  from typing import Literal
4
5
  from collections import deque
5
6
  from pydantic import Field, field_serializer, field_validator, ConfigDict
@@ -14,6 +15,15 @@ from nxtomomill.models.utils import (
14
15
  from ..base.general_section import GeneralSection as _GeneralSectionBase
15
16
 
16
17
 
18
+ def _default_resolve_vds() -> bool:
19
+ """
20
+ Default value for 'resolve_vds'. Fallback on the 'NXTOMOMILL_RESOLVE_VDS'
21
+ environment variable when set, else defaults to True.
22
+ """
23
+ env_value = os.environ.get("NXTOMOMILL_RESOLVE_VDS", True)
24
+ return convert_str_to_bool(env_value)
25
+
26
+
17
27
  class GeneralSection(_GeneralSectionBase):
18
28
  model_config = ConfigDict(validate_assignment=True, validate_by_name=True)
19
29
 
@@ -69,6 +79,17 @@ class GeneralSection(_GeneralSectionBase):
69
79
  default="robust",
70
80
  description="How to open the HDF5 file for reading. Either 'robust' mode (disabling file locking) or 'safe'(with file locking)",
71
81
  )
82
+ resolve_vds: bool = Field(
83
+ default_factory=_default_resolve_vds,
84
+ description=(
85
+ "Resolve external links and virtual datasets (VDS) down to their final "
86
+ "source when building the output NXtomo. Disabling this can speed up "
87
+ "the conversion for datasets with many nested links, at the cost of "
88
+ "the output file containing VDS pointing to other VDS instead of "
89
+ "direct links to the raw data. Defaults to the 'NXTOMOMILL_RESOLVE_VDS' "
90
+ "environment variable if set, else True."
91
+ ),
92
+ )
72
93
 
73
94
  @property
74
95
  def request_input(self) -> bool:
@@ -147,6 +168,7 @@ class GeneralSection(_GeneralSectionBase):
147
168
  "create_control_data",
148
169
  "mechanical_lr_flip",
149
170
  "mechanical_ud_flip",
171
+ "resolve_vds",
150
172
  mode="before",
151
173
  )
152
174
  @classmethod
@@ -57,6 +57,7 @@ class H52nxModel(
57
57
  mechanical_ud_flip=self.mechanical_ud_flip,
58
58
  open_mode_for_reading=self.open_mode_for_reading,
59
59
  output_entries=self.output_entries,
60
+ resolve_vds=self.resolve_vds,
60
61
  ),
61
62
  keys_section=KeysSection(
62
63
  valid_camera_names=self.valid_camera_names,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nxtomomill
3
- Version: 2.2.0.dev0
3
+ Version: 2.2.0.dev1
4
4
  Summary: applications and library to convert raw format to NXtomo format
5
5
  Author-email: Henri Payno <henri.payno@esrf.fr>, Pierre Paleo <pierre.paleo@esrf.fr>, Pierre-Olivier Autran <pierre-olivier.autran@esrf.fr>, Jérôme Lesaint <jerome.lesaint@esrf.fr>, Alessandro Mirone <mirone@esrf.fr>
6
6
  License:
@@ -58,7 +58,7 @@ Requires-Dist: silx>=2.0
58
58
  Requires-Dist: nxtomo>=3.1.0dev1
59
59
  Requires-Dist: pint
60
60
  Requires-Dist: packaging
61
- Requires-Dist: tomoscan[full]>=3.0.0dev0
61
+ Requires-Dist: tomoscan>=3.0.0dev0
62
62
  Requires-Dist: tomobase>=0.0.0dev0
63
63
  Requires-Dist: tqdm
64
64
  Requires-Dist: pydantic
@@ -45,7 +45,6 @@ nxtomomill/converter/version.py
45
45
  nxtomomill/converter/dxfile/__init__.py
46
46
  nxtomomill/converter/dxfile/dxfileconverter.py
47
47
  nxtomomill/converter/dxfile/tests/test_dxfile.py
48
- nxtomomill/converter/edf/_Blosc2Jp2kWrapper.py
49
48
  nxtomomill/converter/edf/__init__.py
50
49
  nxtomomill/converter/edf/checks.py
51
50
  nxtomomill/converter/edf/edfconverter.py
@@ -4,7 +4,7 @@ silx>=2.0
4
4
  nxtomo>=3.1.0dev1
5
5
  pint
6
6
  packaging
7
- tomoscan[full]>=3.0.0dev0
7
+ tomoscan>=3.0.0dev0
8
8
  tomobase>=0.0.0dev0
9
9
  tqdm
10
10
  pydantic
@@ -7,7 +7,7 @@ authors = [
7
7
  { name = "Jérôme Lesaint", email = "jerome.lesaint@esrf.fr" },
8
8
  { name = "Alessandro Mirone", email = "mirone@esrf.fr" }
9
9
  ]
10
- version = "2.2.0dev0"
10
+ version = "2.2.0dev1"
11
11
  description = "applications and library to convert raw format to NXtomo format"
12
12
  readme = { file = "README.md", content-type = "text/markdown" }
13
13
 
@@ -39,7 +39,7 @@ dependencies = [
39
39
  "nxtomo>=3.1.0dev1",
40
40
  "pint",
41
41
  "packaging",
42
- "tomoscan[full] >=3.0.0dev0",
42
+ "tomoscan>=3.0.0dev0",
43
43
  "tomobase>=0.0.0dev0",
44
44
  "tqdm",
45
45
  "pydantic",